@blotout/qinto-cli 0.1.7 → 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 +2163 -1416
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +388 -38
- package/dist/worker-artifact/main/9026260a7a674b710223f296c5d2e7a01930cfed-q.js.txt +1 -0
- package/dist/worker-artifact/main/index.js +467 -50
- 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
|
@@ -15917,7 +15917,14 @@ var scheduleSchema = external_exports.object({
|
|
|
15917
15917
|
id: external_exports.string().min(1).max(32),
|
|
15918
15918
|
cron: external_exports.string().min(1).max(MAX_CRON_LENGTH),
|
|
15919
15919
|
scheduledTime: external_exports.number().int().nonnegative().safe(),
|
|
15920
|
-
installs: external_exports.array(
|
|
15920
|
+
installs: external_exports.array(
|
|
15921
|
+
external_exports.object({
|
|
15922
|
+
id: external_exports.string().min(1).max(64),
|
|
15923
|
+
ord: external_exports.number().int().min(1),
|
|
15924
|
+
label: external_exports.string().max(100),
|
|
15925
|
+
catalogQueryTicket: external_exports.string().min(1).max(2048)
|
|
15926
|
+
}).strict()
|
|
15927
|
+
).min(1).max(MAX_INSTALLS_PER_APP)
|
|
15921
15928
|
}).strict();
|
|
15922
15929
|
var controlEnvelopeSchema = external_exports.object({
|
|
15923
15930
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
@@ -15959,12 +15966,21 @@ var ENDPOINT_CONTEXT_HEADER = "x-qinto-endpoint-context";
|
|
|
15959
15966
|
var ENDPOINT_OUTCOMES_HEADER = "x-qinto-endpoint-outcomes";
|
|
15960
15967
|
var MAX_ENDPOINT_BODY_BYTES = 1024 * 1024;
|
|
15961
15968
|
var MAX_ENDPOINT_OUTCOMES_BYTES = 64 * 1024;
|
|
15969
|
+
var MAX_ENDPOINT_PATH_LENGTH = 16 * 1024;
|
|
15962
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();
|
|
15963
15971
|
var endpointContextSchema = external_exports.object({
|
|
15964
|
-
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({}),
|
|
15965
15980
|
method: external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
15966
15981
|
mode: external_exports.enum(["webhook", "api"]),
|
|
15967
15982
|
version: external_exports.string().min(1).max(32),
|
|
15983
|
+
site: external_exports.object({ origin: external_exports.string().min(1).max(255) }).strict(),
|
|
15968
15984
|
installs: external_exports.array(installSchema3).min(1).max(15)
|
|
15969
15985
|
}).strict().refine((context) => {
|
|
15970
15986
|
return context.mode === "webhook" || context.installs.length === 1;
|
|
@@ -15991,6 +16007,71 @@ var aggregateEndpointOutcomes = /* @__PURE__ */ __name((outcomes) => {
|
|
|
15991
16007
|
return { status: failed ? 502 : 200 };
|
|
15992
16008
|
}, "aggregateEndpointOutcomes");
|
|
15993
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
|
+
|
|
15994
16075
|
// ../../libs/app-envelope/src/ui.ts
|
|
15995
16076
|
var UI_CONTEXT_HEADER = "x-qinto-ui-context";
|
|
15996
16077
|
var MAX_UI_BODY_BYTES = 1024 * 1024;
|
|
@@ -16197,13 +16278,13 @@ var getPattern = /* @__PURE__ */ __name((label, next) => {
|
|
|
16197
16278
|
}
|
|
16198
16279
|
return null;
|
|
16199
16280
|
}, "getPattern");
|
|
16200
|
-
var tryDecode = /* @__PURE__ */ __name((str,
|
|
16281
|
+
var tryDecode = /* @__PURE__ */ __name((str, decoder3) => {
|
|
16201
16282
|
try {
|
|
16202
|
-
return
|
|
16283
|
+
return decoder3(str);
|
|
16203
16284
|
} catch {
|
|
16204
16285
|
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => {
|
|
16205
16286
|
try {
|
|
16206
|
-
return
|
|
16287
|
+
return decoder3(match2);
|
|
16207
16288
|
} catch {
|
|
16208
16289
|
return match2;
|
|
16209
16290
|
}
|
|
@@ -18970,6 +19051,82 @@ var readableContext = /* @__PURE__ */ __name((own, shared) => {
|
|
|
18970
19051
|
return { private: own === void 0 ? null : wireEntry(own), shared: sharedContextWire(shared) };
|
|
18971
19052
|
}, "readableContext");
|
|
18972
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
|
+
|
|
18973
19130
|
// src/apps/read-bounded.ts
|
|
18974
19131
|
var readBoundedBody = /* @__PURE__ */ __name(async (message, maxBytes) => {
|
|
18975
19132
|
const reader = message.body?.getReader();
|
|
@@ -19020,7 +19177,7 @@ var adoptAppSpans = /* @__PURE__ */ __name((response) => {
|
|
|
19020
19177
|
}, "adoptAppSpans");
|
|
19021
19178
|
|
|
19022
19179
|
// src/apps/invoke.ts
|
|
19023
|
-
var
|
|
19180
|
+
var APP_INVOCATION_TIMEOUT_MS = 1e4;
|
|
19024
19181
|
var MAX_EMIT_DEPTH = 2;
|
|
19025
19182
|
var HOOK_URL = "https://app/__qinto/hook";
|
|
19026
19183
|
var invocationContext = /* @__PURE__ */ __name((env) => {
|
|
@@ -19226,19 +19383,24 @@ var hookResponseBody = /* @__PURE__ */ __name(async (response, slug) => {
|
|
|
19226
19383
|
}
|
|
19227
19384
|
return new TextDecoder().decode(bytes);
|
|
19228
19385
|
}, "hookResponseBody");
|
|
19229
|
-
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 }) => {
|
|
19230
19387
|
try {
|
|
19231
19388
|
const key = await deriveAppInternalKey(context.master, context.domainId, target.slug);
|
|
19232
19389
|
const response = await postHookEnvelope(env, {
|
|
19233
19390
|
binding: target.app.binding,
|
|
19234
19391
|
key,
|
|
19235
19392
|
envelope: buildEnvelope(target, trigger, snapshot, context),
|
|
19236
|
-
timeoutMs:
|
|
19393
|
+
timeoutMs: APP_INVOCATION_TIMEOUT_MS
|
|
19237
19394
|
});
|
|
19238
19395
|
if (response === void 0) {
|
|
19239
19396
|
addSpanEvent("app service binding is missing", { level: "warn", attrs: { app: target.slug, binding: target.app.binding } });
|
|
19240
19397
|
return;
|
|
19241
19398
|
}
|
|
19399
|
+
writeAppObservability(env, response, {
|
|
19400
|
+
app: observabilityApp(target.slug, target.app),
|
|
19401
|
+
installs: target.installs,
|
|
19402
|
+
budget
|
|
19403
|
+
});
|
|
19242
19404
|
setSpanAttributes({ "app.status": response.status });
|
|
19243
19405
|
const body = await hookResponseBody(response, target.slug);
|
|
19244
19406
|
if (body === void 0) {
|
|
@@ -19322,6 +19484,9 @@ var installSchema4 = external_exports.object({
|
|
|
19322
19484
|
});
|
|
19323
19485
|
var appSchema = external_exports.object({
|
|
19324
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),
|
|
19325
19490
|
version: external_exports.string().min(1),
|
|
19326
19491
|
// Absent from an old embedded registry; the default never equals a real claim, so the ui proxy
|
|
19327
19492
|
// refuses stale registries with token_stale instead of turning the app off.
|
|
@@ -19609,11 +19774,16 @@ var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, in
|
|
|
19609
19774
|
// JSON.stringify drops an undefined key, and the envelope requires `args` to be present.
|
|
19610
19775
|
rpc: { caller: body.slug, fn: body.fn, args: body.args ?? null }
|
|
19611
19776
|
},
|
|
19612
|
-
timeoutMs:
|
|
19777
|
+
timeoutMs: APP_INVOCATION_TIMEOUT_MS
|
|
19613
19778
|
});
|
|
19614
19779
|
if (response === void 0) {
|
|
19615
19780
|
return calleeFailed(body.callee, "The callee service binding is missing.");
|
|
19616
19781
|
}
|
|
19782
|
+
writeAppObservability(env, response, {
|
|
19783
|
+
app: observabilityApp(body.callee, callee),
|
|
19784
|
+
installs: [install],
|
|
19785
|
+
budget: createDataPointBudget()
|
|
19786
|
+
});
|
|
19617
19787
|
setSpanAttributes({ "app.status": response.status });
|
|
19618
19788
|
if (!response.ok) {
|
|
19619
19789
|
return calleeFailed(body.callee, `The callee answered status ${response.status}.`);
|
|
@@ -19881,6 +20051,18 @@ var controlTargets = /* @__PURE__ */ __name(() => {
|
|
|
19881
20051
|
// src/apps/control.ts
|
|
19882
20052
|
var CONTROL_PATH = "/__qinto/control";
|
|
19883
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");
|
|
19884
20066
|
var textBody = /* @__PURE__ */ __name(async (request) => {
|
|
19885
20067
|
const bytes = await readBoundedBody(request, MAX_CONTROL_BYTES);
|
|
19886
20068
|
return bytes === null ? null : new TextDecoder().decode(bytes);
|
|
@@ -19949,6 +20131,7 @@ var handleControl = /* @__PURE__ */ __name(async (request, env) => {
|
|
|
19949
20131
|
signal: AbortSignal.timeout(1e4)
|
|
19950
20132
|
});
|
|
19951
20133
|
adoptAppSpans(upstream);
|
|
20134
|
+
writeControlObservability(env, upstream, envelope);
|
|
19952
20135
|
const responseBytes = await readBoundedBody(upstream, MAX_CONTROL_BYTES);
|
|
19953
20136
|
if (responseBytes === null) {
|
|
19954
20137
|
return Response.json({ error: "invalid_response" }, { status: 502 });
|
|
@@ -19967,6 +20150,73 @@ var appControlRoutes = new Hono2().post(CONTROL_PATH, (c) => {
|
|
|
19967
20150
|
return handleControl(c.req.raw, c.env);
|
|
19968
20151
|
});
|
|
19969
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
|
+
|
|
19970
20220
|
// ../../libs/worker-access-token/src/endpoints.ts
|
|
19971
20221
|
var APP_ENDPOINT_PREFIX = "/app/";
|
|
19972
20222
|
var MAX_CUSTOM_ENDPOINT_LENGTH = 128;
|
|
@@ -20202,7 +20452,76 @@ var requireScope = /* @__PURE__ */ __name((bit) => {
|
|
|
20202
20452
|
};
|
|
20203
20453
|
}, "requireScope");
|
|
20204
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
|
+
|
|
20205
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;
|
|
20206
20525
|
var DENIED_REQUEST_HEADERS = /* @__PURE__ */ new Set(["authorization", "cookie", "x-cf-data"]);
|
|
20207
20526
|
var refuse = /* @__PURE__ */ __name((status, error51) => {
|
|
20208
20527
|
return Response.json({ error: error51 }, { status });
|
|
@@ -20218,16 +20537,23 @@ var matchEndpoint = /* @__PURE__ */ __name((app2, path, method) => {
|
|
|
20218
20537
|
if (!isHttpMethod(method)) {
|
|
20219
20538
|
return void 0;
|
|
20220
20539
|
}
|
|
20221
|
-
const
|
|
20222
|
-
return endpoint.
|
|
20540
|
+
const serving = app2.endpoints.filter((endpoint) => {
|
|
20541
|
+
return endpoint.methods.includes(method);
|
|
20223
20542
|
});
|
|
20224
|
-
|
|
20543
|
+
const matched = matchEndpointPath(
|
|
20544
|
+
serving.map((endpoint) => endpoint.path),
|
|
20545
|
+
path
|
|
20546
|
+
);
|
|
20547
|
+
if (matched === void 0) {
|
|
20225
20548
|
return void 0;
|
|
20226
20549
|
}
|
|
20550
|
+
const declared = serving.find((endpoint) => {
|
|
20551
|
+
return endpoint.path === matched.route;
|
|
20552
|
+
});
|
|
20227
20553
|
if (declared.auth !== "public" && declared.auth !== "token" || declared.mode !== "webhook" && declared.mode !== "api") {
|
|
20228
20554
|
return void 0;
|
|
20229
20555
|
}
|
|
20230
|
-
return {
|
|
20556
|
+
return { route: declared.path, path, params: matched.params, method, auth: declared.auth, mode: declared.mode };
|
|
20231
20557
|
}, "matchEndpoint");
|
|
20232
20558
|
var authorizeEndpoint = /* @__PURE__ */ __name(async (c, slug, endpoint) => {
|
|
20233
20559
|
if (endpoint.auth === "public") {
|
|
@@ -20259,12 +20585,17 @@ var passThroughResponse = /* @__PURE__ */ __name((upstream) => {
|
|
|
20259
20585
|
const headers = new Headers(upstream.headers);
|
|
20260
20586
|
headers.delete("set-cookie");
|
|
20261
20587
|
headers.delete(APP_SPANS_HEADER);
|
|
20588
|
+
headers.delete(APP_OBSERVABILITY_HEADER);
|
|
20262
20589
|
for (const name of [...headers.keys()]) {
|
|
20263
20590
|
if (name.startsWith("access-control-")) {
|
|
20264
20591
|
headers.delete(name);
|
|
20265
20592
|
}
|
|
20266
20593
|
}
|
|
20267
|
-
|
|
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 });
|
|
20268
20599
|
}, "passThroughResponse");
|
|
20269
20600
|
var parseJson3 = /* @__PURE__ */ __name((text) => {
|
|
20270
20601
|
try {
|
|
@@ -20294,6 +20625,17 @@ var webhookAck = /* @__PURE__ */ __name(async (slug, upstream) => {
|
|
|
20294
20625
|
}
|
|
20295
20626
|
return refuse(502, "upstream");
|
|
20296
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");
|
|
20297
20639
|
var runForwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
20298
20640
|
const { slug, app: app2, endpoint, installs, body, search } = input;
|
|
20299
20641
|
const context = invocationContext(c.env);
|
|
@@ -20313,25 +20655,30 @@ var runForwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20313
20655
|
headers.set(
|
|
20314
20656
|
ENDPOINT_CONTEXT_HEADER,
|
|
20315
20657
|
JSON.stringify({
|
|
20658
|
+
route: endpoint.route,
|
|
20316
20659
|
path: endpoint.path,
|
|
20660
|
+
params: endpoint.params,
|
|
20317
20661
|
method: endpoint.method,
|
|
20318
20662
|
mode: endpoint.mode,
|
|
20319
20663
|
version: app2.version,
|
|
20664
|
+
site: { origin: context.origin },
|
|
20320
20665
|
installs: installs.map((install) => ({ id: install.id, ord: install.ord, label: install.label }))
|
|
20321
20666
|
})
|
|
20322
20667
|
);
|
|
20323
20668
|
let upstream;
|
|
20324
20669
|
try {
|
|
20325
|
-
|
|
20326
|
-
|
|
20327
|
-
|
|
20328
|
-
body,
|
|
20329
|
-
signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
|
|
20330
|
-
});
|
|
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) });
|
|
20331
20673
|
} catch (error51) {
|
|
20332
20674
|
return upstreamFailed(slug, String(error51));
|
|
20333
20675
|
}
|
|
20334
20676
|
adoptAppSpans(upstream);
|
|
20677
|
+
writeAppObservability(c.env, upstream, {
|
|
20678
|
+
app: observabilityApp(slug, app2),
|
|
20679
|
+
installs,
|
|
20680
|
+
budget: createDataPointBudget()
|
|
20681
|
+
});
|
|
20335
20682
|
setSpanAttributes({ "app.status": upstream.status });
|
|
20336
20683
|
return endpoint.mode === "api" ? passThroughResponse(upstream) : webhookAck(slug, upstream);
|
|
20337
20684
|
}, "runForwardToApp");
|
|
@@ -20344,7 +20691,7 @@ var forwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20344
20691
|
"app.slug": slug,
|
|
20345
20692
|
"app.version": app2.version,
|
|
20346
20693
|
"app.binding": app2.binding,
|
|
20347
|
-
"app.hook": `endpoint.${endpoint.method} ${endpoint.
|
|
20694
|
+
"app.hook": `endpoint.${endpoint.method} ${endpoint.route}`,
|
|
20348
20695
|
"app.endpoint_mode": endpoint.mode,
|
|
20349
20696
|
"app.installs": installs.length
|
|
20350
20697
|
}
|
|
@@ -20360,7 +20707,11 @@ var handleAppEndpoint = /* @__PURE__ */ __name(async (c, slug) => {
|
|
|
20360
20707
|
return refuse(404, "not_found");
|
|
20361
20708
|
}
|
|
20362
20709
|
const url2 = new URL(c.req.url);
|
|
20363
|
-
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);
|
|
20364
20715
|
if (endpoint === void 0) {
|
|
20365
20716
|
return refuse(404, "not_found");
|
|
20366
20717
|
}
|
|
@@ -20373,7 +20724,7 @@ var handleAppEndpoint = /* @__PURE__ */ __name(async (c, slug) => {
|
|
|
20373
20724
|
if (first === void 0) {
|
|
20374
20725
|
return refuse(503, "inactive");
|
|
20375
20726
|
}
|
|
20376
|
-
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`;
|
|
20377
20728
|
if (await rateLimited(c.env, key)) {
|
|
20378
20729
|
return refuse(429, "rate_limited");
|
|
20379
20730
|
}
|
|
@@ -20540,10 +20891,24 @@ var verifyAppUiToken = /* @__PURE__ */ __name(async (input) => {
|
|
|
20540
20891
|
return { ok: true, claims: claims.data, kid: signature.kid, key: signature.key };
|
|
20541
20892
|
}, "verifyAppUiToken");
|
|
20542
20893
|
|
|
20894
|
+
// ../../libs/app-ui-token/src/schedule-catalog-ticket.ts
|
|
20895
|
+
var APP_SCHEDULE_CATALOG_TICKET_ISSUER = "qinto-portal";
|
|
20896
|
+
var claimsSchema2 = external_exports.object({
|
|
20897
|
+
iss: external_exports.literal(APP_SCHEDULE_CATALOG_TICKET_ISSUER),
|
|
20898
|
+
aud: external_exports.string().min(1),
|
|
20899
|
+
sub: external_exports.string().min(1),
|
|
20900
|
+
iat: external_exports.number().int(),
|
|
20901
|
+
exp: external_exports.number().int(),
|
|
20902
|
+
domainId: external_exports.string().min(1),
|
|
20903
|
+
appId: external_exports.string().min(1),
|
|
20904
|
+
appInstallId: external_exports.string().min(1),
|
|
20905
|
+
appVersionId: external_exports.string().min(1)
|
|
20906
|
+
}).strict();
|
|
20907
|
+
|
|
20543
20908
|
// ../../libs/app-ui-token/src/write-ticket.ts
|
|
20544
20909
|
var APP_UI_WRITE_TICKET_TTL_SECONDS = 60;
|
|
20545
20910
|
var APP_UI_WRITE_TICKET_ISSUER = "qinto-site";
|
|
20546
|
-
var
|
|
20911
|
+
var claimsSchema3 = external_exports.object({
|
|
20547
20912
|
iss: external_exports.literal(APP_UI_WRITE_TICKET_ISSUER),
|
|
20548
20913
|
aud: external_exports.string().min(1),
|
|
20549
20914
|
sub: external_exports.string().min(1),
|
|
@@ -20629,16 +20994,22 @@ var runForwardToApp2 = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20629
20994
|
method: c.req.method,
|
|
20630
20995
|
headers,
|
|
20631
20996
|
body,
|
|
20632
|
-
signal: AbortSignal.timeout(
|
|
20997
|
+
signal: AbortSignal.timeout(APP_INVOCATION_TIMEOUT_MS)
|
|
20633
20998
|
});
|
|
20634
20999
|
} catch (error51) {
|
|
20635
21000
|
return upstreamFailed2(origin, slug, String(error51));
|
|
20636
21001
|
}
|
|
20637
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
|
+
});
|
|
20638
21008
|
setSpanAttributes({ "app.status": upstream.status });
|
|
20639
21009
|
const responseHeaders = new Headers(upstream.headers);
|
|
20640
21010
|
responseHeaders.delete("set-cookie");
|
|
20641
21011
|
responseHeaders.delete(APP_SPANS_HEADER);
|
|
21012
|
+
responseHeaders.delete(APP_OBSERVABILITY_HEADER);
|
|
20642
21013
|
for (const name of [...responseHeaders.keys()]) {
|
|
20643
21014
|
if (name.startsWith("access-control-")) {
|
|
20644
21015
|
responseHeaders.delete(name);
|
|
@@ -23672,6 +24043,21 @@ var withoutQuery = /* @__PURE__ */ __name((url2) => {
|
|
|
23672
24043
|
parsed.search = "";
|
|
23673
24044
|
return parsed.toString();
|
|
23674
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");
|
|
23675
24061
|
var connectionAttachment = /* @__PURE__ */ __name((request, geo) => {
|
|
23676
24062
|
const userAgent = request.headers.get("user-agent");
|
|
23677
24063
|
const attrs = {
|
|
@@ -23687,15 +24073,18 @@ var connectionAttachment = /* @__PURE__ */ __name((request, geo) => {
|
|
|
23687
24073
|
locale: raw2.locale !== void 0 && raw2.locale.length <= MAX_HOST_LOCALE_LENGTH ? raw2.locale : void 0
|
|
23688
24074
|
};
|
|
23689
24075
|
const host = bounded.ip === void 0 && bounded.userAgent === void 0 && bounded.locale === void 0 ? void 0 : bounded;
|
|
23690
|
-
const hostBytes =
|
|
24076
|
+
const hostBytes = attachmentFieldBytes("host", host);
|
|
24077
|
+
const browserGeo = browserGeoFrom(geo);
|
|
24078
|
+
const browserGeoBytes = attachmentFieldBytes("browserGeo", browserGeo);
|
|
23691
24079
|
const cf = forwardedCf(request);
|
|
23692
24080
|
const cfSuffix = cf === void 0 ? "" : `,"cf":${JSON.stringify(cf)}`;
|
|
23693
24081
|
const cfBytes = new TextEncoder().encode(cfSuffix).length;
|
|
23694
24082
|
const emptyAttrsBytes = new TextEncoder().encode(JSON.stringify({ attrs: {} })).length;
|
|
23695
|
-
const includedCf = cfBytes <= MAX_ATTACHMENT_BYTES - emptyAttrsBytes - hostBytes ? cf : void 0;
|
|
23696
|
-
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));
|
|
23697
24085
|
return {
|
|
23698
24086
|
...budgeted,
|
|
24087
|
+
...browserGeo === void 0 ? {} : { browserGeo },
|
|
23699
24088
|
...includedCf === void 0 ? {} : { cf: includedCf },
|
|
23700
24089
|
...host === void 0 ? {} : { host }
|
|
23701
24090
|
};
|
|
@@ -23782,14 +24171,14 @@ var open = /* @__PURE__ */ __name(async (c) => {
|
|
|
23782
24171
|
|
|
23783
24172
|
// browser-artifact/meta.json
|
|
23784
24173
|
var meta_default = {
|
|
23785
|
-
version: "0.1.
|
|
23786
|
-
gitSha: "
|
|
23787
|
-
builtAt: "2026-08-
|
|
23788
|
-
hash: "
|
|
24174
|
+
version: "0.1.3",
|
|
24175
|
+
gitSha: "66e1bc45acbe4891948cbb3851f3f43ce06abc84",
|
|
24176
|
+
builtAt: "2026-08-28T17:17:19.113Z",
|
|
24177
|
+
hash: "050bb7dd702ac407623ce130c324f3342f048b8a201e2975994d5ef54de7f19f"
|
|
23789
24178
|
};
|
|
23790
24179
|
|
|
23791
24180
|
// src/paths/q-js.ts
|
|
23792
|
-
import qScript from "./
|
|
24181
|
+
import qScript from "./9026260a7a674b710223f296c5d2e7a01930cfed-q.js.txt";
|
|
23793
24182
|
|
|
23794
24183
|
// src/apps-q.ts
|
|
23795
24184
|
import appsQScript from "./apps-q.json";
|
|
@@ -23846,6 +24235,7 @@ var appsMetadata = /* @__PURE__ */ __name(() => {
|
|
|
23846
24235
|
return Object.fromEntries(
|
|
23847
24236
|
Object.entries(registry3.apps).map(([slug, app2]) => {
|
|
23848
24237
|
const capture = declaredCapture(app2);
|
|
24238
|
+
const geo = app2.data.includes("geo") ? { geo: true } : {};
|
|
23849
24239
|
const sharedContext = app2.data.includes(SHARED_CONTEXT_CAPABILITY) ? { sharedContext: true } : {};
|
|
23850
24240
|
return [
|
|
23851
24241
|
slug,
|
|
@@ -23853,6 +24243,7 @@ var appsMetadata = /* @__PURE__ */ __name(() => {
|
|
|
23853
24243
|
category: app2.consent.category,
|
|
23854
24244
|
eventResults: app2.eventResults,
|
|
23855
24245
|
...capture === void 0 ? {} : { capture },
|
|
24246
|
+
...geo,
|
|
23856
24247
|
...sharedContext
|
|
23857
24248
|
}
|
|
23858
24249
|
];
|
|
@@ -24499,7 +24890,7 @@ var runPool = /* @__PURE__ */ __name(async (limit, tasks) => {
|
|
|
24499
24890
|
}
|
|
24500
24891
|
await Promise.all(running);
|
|
24501
24892
|
}, "runPool");
|
|
24502
|
-
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 }) => {
|
|
24503
24894
|
const { registry: registry3, error: error51 } = siteRegistry();
|
|
24504
24895
|
const targets = eligibleApps(registry3, trigger, snapshot.consent, consentEnforced(env));
|
|
24505
24896
|
if (error51 === void 0 && targets.length === 0) {
|
|
@@ -24527,7 +24918,7 @@ var fanOutToApps = /* @__PURE__ */ __name(async (env, trigger, snapshot, { deliv
|
|
|
24527
24918
|
await runPool(
|
|
24528
24919
|
FAN_OUT_CONCURRENCY,
|
|
24529
24920
|
capped.map((target) => {
|
|
24530
|
-
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 });
|
|
24531
24922
|
})
|
|
24532
24923
|
);
|
|
24533
24924
|
}
|
|
@@ -24584,7 +24975,7 @@ var withReplacedPayload = /* @__PURE__ */ __name((entry, action, payload) => {
|
|
|
24584
24975
|
}
|
|
24585
24976
|
return { ...action, payload: parsed.data };
|
|
24586
24977
|
}, "withReplacedPayload");
|
|
24587
|
-
var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
24978
|
+
var postTransform = /* @__PURE__ */ __name(async (env, entry, post, dataPoints) => {
|
|
24588
24979
|
let response;
|
|
24589
24980
|
try {
|
|
24590
24981
|
response = await postHookEnvelope(env, { binding: entry.app.binding, ...post });
|
|
@@ -24594,6 +24985,11 @@ var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
|
24594
24985
|
if (response === void 0) {
|
|
24595
24986
|
throw entryFailure(entry, `the ${entry.app.binding} service binding is missing`);
|
|
24596
24987
|
}
|
|
24988
|
+
writeAppObservability(env, response, {
|
|
24989
|
+
app: observabilityApp(entry.slug, entry.app),
|
|
24990
|
+
installs: [entry.install],
|
|
24991
|
+
budget: dataPoints
|
|
24992
|
+
});
|
|
24597
24993
|
setSpanAttributes({ "app.status": response.status });
|
|
24598
24994
|
if (!response.ok) {
|
|
24599
24995
|
throw entryFailure(entry, `the hook answered status ${response.status}`);
|
|
@@ -24608,14 +25004,14 @@ var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
|
24608
25004
|
throw entryFailure(entry, String(error51));
|
|
24609
25005
|
}
|
|
24610
25006
|
}, "postTransform");
|
|
24611
|
-
var runTransformEntry = /* @__PURE__ */ __name(async (env, { entry, action, snapshot, context, timeoutMs }) => {
|
|
25007
|
+
var runTransformEntry = /* @__PURE__ */ __name(async (env, { entry, action, snapshot, context, timeoutMs, dataPoints }) => {
|
|
24612
25008
|
const target = { slug: entry.slug, app: entry.app, installs: [entry.install] };
|
|
24613
25009
|
const envelope = {
|
|
24614
25010
|
...buildEnvelope(target, { kind: "event", action }, snapshot, context),
|
|
24615
25011
|
kind: "transform"
|
|
24616
25012
|
};
|
|
24617
25013
|
const key = await deriveAppInternalKey(context.master, context.domainId, entry.slug);
|
|
24618
|
-
const verdict = validateEnvelopeResponse(await postTransform(env, entry, { key, envelope, timeoutMs }), 1);
|
|
25014
|
+
const verdict = validateEnvelopeResponse(await postTransform(env, entry, { key, envelope, timeoutMs }, dataPoints), 1);
|
|
24619
25015
|
if (!verdict.ok) {
|
|
24620
25016
|
throw entryFailure(entry, verdict.reason);
|
|
24621
25017
|
}
|
|
@@ -24683,7 +25079,7 @@ var buildRelease = /* @__PURE__ */ __name((env, { collected, action, deliverPush
|
|
|
24683
25079
|
}
|
|
24684
25080
|
};
|
|
24685
25081
|
}, "buildRelease");
|
|
24686
|
-
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 }) => {
|
|
24687
25083
|
const { registry: registry3, error: error51 } = siteRegistry();
|
|
24688
25084
|
if (error51 !== void 0) {
|
|
24689
25085
|
throw new TransformChainError(`the apps registry is malformed: ${error51}`);
|
|
@@ -24703,7 +25099,14 @@ var runTransformChain = /* @__PURE__ */ __name(async (env, { action, snapshot, d
|
|
|
24703
25099
|
for (const entry of entries) {
|
|
24704
25100
|
const stepped = entryBudget(budget, entry, Date.now());
|
|
24705
25101
|
budget = stepped.budget;
|
|
24706
|
-
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
|
+
});
|
|
24707
25110
|
if (verdict.effects.accepted.length > 0) {
|
|
24708
25111
|
collected.push({ slug: entry.slug, installs: [entry.install], groups: verdict.effects.accepted });
|
|
24709
25112
|
}
|
|
@@ -25684,7 +26087,11 @@ var AnonDO = class extends DurableObject2 {
|
|
|
25684
26087
|
const attachment = connectionAttachment(request, geo);
|
|
25685
26088
|
server.serializeAttachment(attachment);
|
|
25686
26089
|
this.deliverSharedContext(server);
|
|
25687
|
-
this.appFanOut(
|
|
26090
|
+
this.appFanOut(
|
|
26091
|
+
{ kind: "connect", ...attachment.cf === void 0 ? {} : { geo: attachment.cf }, host: attachment.host },
|
|
26092
|
+
userId,
|
|
26093
|
+
createDataPointBudget()
|
|
26094
|
+
);
|
|
25688
26095
|
return new Response(null, { status: 101, webSocket: client });
|
|
25689
26096
|
});
|
|
25690
26097
|
}
|
|
@@ -25739,7 +26146,14 @@ var AnonDO = class extends DurableObject2 {
|
|
|
25739
26146
|
return;
|
|
25740
26147
|
}
|
|
25741
26148
|
if (parsed.frame.t === "getSession") {
|
|
25742
|
-
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
|
+
});
|
|
25743
26157
|
return;
|
|
25744
26158
|
}
|
|
25745
26159
|
if (parsed.frame.t === "capture") {
|
|
@@ -26025,12 +26439,13 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26025
26439
|
if (isNoopAction(action)) {
|
|
26026
26440
|
return;
|
|
26027
26441
|
}
|
|
26028
|
-
const
|
|
26442
|
+
const dataPoints = createDataPointBudget();
|
|
26443
|
+
const transformed = await this.transformAction(action, dataPoints);
|
|
26029
26444
|
if (transformed === null) {
|
|
26030
26445
|
return;
|
|
26031
26446
|
}
|
|
26032
26447
|
recorded = transformed.action;
|
|
26033
|
-
await this.runAction(transformed.action, transformed.releaseEmissions);
|
|
26448
|
+
await this.runAction(transformed.action, transformed.releaseEmissions, dataPoints);
|
|
26034
26449
|
} finally {
|
|
26035
26450
|
this.recordActionBlocks(recorded);
|
|
26036
26451
|
}
|
|
@@ -26040,9 +26455,9 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26040
26455
|
actionBlocks(action, this.appsSnapshot(action.userId), this.wiped ? [] : allIdentifiers(this.sql, this.identifiersMirror))
|
|
26041
26456
|
);
|
|
26042
26457
|
}
|
|
26043
|
-
async runAction(current, releaseEmissions) {
|
|
26458
|
+
async runAction(current, releaseEmissions, dataPoints) {
|
|
26044
26459
|
if (current.type !== "alias" && isDeliveryOnlyAction(current)) {
|
|
26045
|
-
this.appFanOut({ kind: "event", action: current }, current.userId);
|
|
26460
|
+
this.appFanOut({ kind: "event", action: current }, current.userId, dataPoints);
|
|
26046
26461
|
this.releaseTransformEmissions(releaseEmissions);
|
|
26047
26462
|
return;
|
|
26048
26463
|
}
|
|
@@ -26078,7 +26493,7 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26078
26493
|
} else {
|
|
26079
26494
|
await this.ingestConsent(current);
|
|
26080
26495
|
}
|
|
26081
|
-
this.appFanOut({ kind: "event", action: current }, current.userId);
|
|
26496
|
+
this.appFanOut({ kind: "event", action: current }, current.userId, dataPoints);
|
|
26082
26497
|
this.releaseTransformEmissions(releaseEmissions);
|
|
26083
26498
|
} finally {
|
|
26084
26499
|
if (novelIdentifier) {
|
|
@@ -26087,7 +26502,7 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26087
26502
|
}
|
|
26088
26503
|
}
|
|
26089
26504
|
// null means a transform dropped the action: the turn succeeds with nothing persisted (§5.4).
|
|
26090
|
-
async transformAction(action) {
|
|
26505
|
+
async transformAction(action, dataPoints) {
|
|
26091
26506
|
if (action.type !== "track" && action.type !== "identify") {
|
|
26092
26507
|
return { action, releaseEmissions: null };
|
|
26093
26508
|
}
|
|
@@ -26096,7 +26511,8 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26096
26511
|
snapshot: this.appsSnapshot(action.userId),
|
|
26097
26512
|
deliverPush: this.pushDelivery,
|
|
26098
26513
|
writeAttribution: this.attributionDelivery,
|
|
26099
|
-
writeContext: this.contextDelivery
|
|
26514
|
+
writeContext: this.contextDelivery,
|
|
26515
|
+
dataPoints
|
|
26100
26516
|
});
|
|
26101
26517
|
if (outcome.dropped) {
|
|
26102
26518
|
this.releaseTransformEmissions(outcome.releaseEmissions);
|
|
@@ -26132,13 +26548,14 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26132
26548
|
}
|
|
26133
26549
|
this.ctx.waitUntil(release().catch((error51) => console.warn("transform emission release failed", { error: error51 })));
|
|
26134
26550
|
}
|
|
26135
|
-
appFanOut(trigger, anonId) {
|
|
26551
|
+
appFanOut(trigger, anonId, dataPoints) {
|
|
26136
26552
|
const snapshot = this.appsSnapshot(anonId);
|
|
26137
26553
|
this.ctx.waitUntil(
|
|
26138
26554
|
fanOutToApps(this.env, trigger, snapshot, {
|
|
26139
26555
|
deliverPush: this.pushDelivery,
|
|
26140
26556
|
writeAttribution: this.attributionDelivery,
|
|
26141
26557
|
writeContext: this.contextDelivery,
|
|
26558
|
+
budget: dataPoints,
|
|
26142
26559
|
trace: currentTraceContext()
|
|
26143
26560
|
}).catch((error51) => console.warn("app fan-out failed", { error: error51 }))
|
|
26144
26561
|
);
|