@blotout/qinto-cli 0.1.21 → 0.1.23
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/README.md +31 -11
- package/dist/index.js +4686 -4295
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +259 -98
- package/dist/worker-artifact/main/944c722e73fe144b1067da970f87716a835c697e-q.js.txt +1 -0
- package/dist/worker-artifact/main/index.js +480 -66
- package/dist/worker-artifact/version.json +12 -11
- package/dist/worker-artifact/wfp/index.js +1 -1
- package/package.json +1 -1
- package/dist/worker-artifact/main/7bc13565a6fa9d520d0ebed788d11591e8db5b44-q.js.txt +0 -1
|
@@ -4,6 +4,10 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
// ../../../libs/app-manifest/src/app-roles.ts
|
|
8
|
+
var DECLARABLE_APP_ROLES = ["owner", "admin", "manager", "editor", "member", "viewer"];
|
|
9
|
+
var APP_ROLES = ["full", ...DECLARABLE_APP_ROLES];
|
|
10
|
+
|
|
7
11
|
// ../../../libs/app-manifest/src/cron.ts
|
|
8
12
|
var MAX_CRON_LENGTH = 128;
|
|
9
13
|
var MINUTE_LITERAL = /^([0-9]|[1-5][0-9])$/;
|
|
@@ -18947,6 +18951,10 @@ var VARIABLE_NAME = /^[A-Z][A-Z0-9_]*$/;
|
|
|
18947
18951
|
var APP_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,29}$/;
|
|
18948
18952
|
var FUNCTION_NAME = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
18949
18953
|
var identifierField = external_exports.string().min(1).max(64).regex(IDENTIFIER);
|
|
18954
|
+
var RENDERABLE_TEXT = /^[^\u0000-\u0009\u000B-\u001F\u007F\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF]*$/;
|
|
18955
|
+
var renderableText = (min, max) => {
|
|
18956
|
+
return external_exports.string().min(min).max(max).regex(RENDERABLE_TEXT, "must not carry control or bidirectional-override characters");
|
|
18957
|
+
};
|
|
18950
18958
|
var httpsUrl = (field2) => {
|
|
18951
18959
|
return external_exports.url().max(2048).refine((value) => value.startsWith("https://"), `${field2} must be an HTTPS URL`);
|
|
18952
18960
|
};
|
|
@@ -19082,6 +19090,35 @@ var validateOauth = (input2, ctx) => {
|
|
|
19082
19090
|
}
|
|
19083
19091
|
};
|
|
19084
19092
|
|
|
19093
|
+
// ../../../libs/app-manifest/src/roles.ts
|
|
19094
|
+
var MAX_APP_ROLE_DESCRIPTION = 200;
|
|
19095
|
+
var roleSchema = external_exports.object({
|
|
19096
|
+
key: external_exports.enum(DECLARABLE_APP_ROLES, {
|
|
19097
|
+
error: (issue2) => {
|
|
19098
|
+
return issue2.input === "full" ? "full access is always available and is not declared" : void 0;
|
|
19099
|
+
}
|
|
19100
|
+
}),
|
|
19101
|
+
description: renderableText(1, MAX_APP_ROLE_DESCRIPTION).optional()
|
|
19102
|
+
}).strict();
|
|
19103
|
+
var rolesSchema = external_exports.array(roleSchema).max(DECLARABLE_APP_ROLES.length).superRefine((roles, ctx) => {
|
|
19104
|
+
uniqueOrIssue(
|
|
19105
|
+
ctx,
|
|
19106
|
+
roles.map((role) => role.key),
|
|
19107
|
+
[],
|
|
19108
|
+
"role"
|
|
19109
|
+
);
|
|
19110
|
+
}).transform((roles) => {
|
|
19111
|
+
return [...roles].sort((a, b) => APP_ROLES.indexOf(a.key) - APP_ROLES.indexOf(b.key));
|
|
19112
|
+
});
|
|
19113
|
+
var validateRoles = (manifest, ctx) => {
|
|
19114
|
+
const declared = /* @__PURE__ */ new Set(["full", ...(manifest.roles ?? []).map((role) => role.key)]);
|
|
19115
|
+
for (const [index, tool] of manifest.tools.entries()) {
|
|
19116
|
+
if (tool.role !== void 0 && !declared.has(tool.role)) {
|
|
19117
|
+
ctx.addIssue({ code: "custom", path: ["tools", index, "role"], message: `Tool role ${tool.role} is not declared in roles` });
|
|
19118
|
+
}
|
|
19119
|
+
}
|
|
19120
|
+
};
|
|
19121
|
+
|
|
19085
19122
|
// ../../../libs/app-manifest/src/route.ts
|
|
19086
19123
|
var ENDPOINT_PATH_PATTERN = /^\/(?:(?::[a-zA-Z][a-zA-Z0-9_]*|[a-zA-Z0-9_-]+)(?:\/(?::[a-zA-Z][a-zA-Z0-9_]*|[a-zA-Z0-9_-]+))*)?$/;
|
|
19087
19124
|
var isParam = (segment) => {
|
|
@@ -19115,10 +19152,6 @@ var MAX_MANIFEST_TOOLS_BYTES = 150 * 1024;
|
|
|
19115
19152
|
var TOOL_PROPERTY_NAME = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
19116
19153
|
var RESERVED_TOOL_ARGUMENTS = ["teamId", "siteId", "installId"];
|
|
19117
19154
|
var TOOL_STRING_FORMATS = ["uuid", "date", "date-time", "email", "uri"];
|
|
19118
|
-
var RENDERABLE_TEXT = /^[^\u0000-\u0009\u000B-\u001F\u007F\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF]*$/;
|
|
19119
|
-
var renderableText = (min, max) => {
|
|
19120
|
-
return external_exports.string().min(min).max(max).regex(RENDERABLE_TEXT, "must not carry control or bidirectional-override characters");
|
|
19121
|
-
};
|
|
19122
19155
|
var propertyName = external_exports.string().min(1).max(48).regex(TOOL_PROPERTY_NAME);
|
|
19123
19156
|
var FORMAT_SCHEMAS = {
|
|
19124
19157
|
uuid: external_exports.uuid(),
|
|
@@ -19214,7 +19247,8 @@ var toolSchema = external_exports.object({
|
|
|
19214
19247
|
title: renderableText(1, MAX_APP_TOOL_TITLE_LENGTH),
|
|
19215
19248
|
description: renderableText(MIN_APP_TOOL_DESCRIPTION, MAX_APP_TOOL_DESCRIPTION),
|
|
19216
19249
|
inputSchema: toolInputSchema,
|
|
19217
|
-
annotations: toolAnnotationsSchema
|
|
19250
|
+
annotations: toolAnnotationsSchema,
|
|
19251
|
+
role: external_exports.enum(APP_ROLES).optional()
|
|
19218
19252
|
}).strict();
|
|
19219
19253
|
var nodeChildren = (value) => {
|
|
19220
19254
|
const properties = value["properties"];
|
|
@@ -19618,6 +19652,9 @@ var baseSchema = external_exports.object({
|
|
|
19618
19652
|
description: "The push topics this app broadcasts to every app on the site. Requires the `sharedContext` data capability; a topic left out reaches only this app\u2019s own browser code."
|
|
19619
19653
|
}),
|
|
19620
19654
|
endpoints: external_exports.array(endpointSchema).max(16).default([]).meta({ description: "The HTTP routes served at https://<site>/app/<slug><path>." }),
|
|
19655
|
+
roles: rolesSchema.optional().meta({
|
|
19656
|
+
description: "The app roles this app uses, from the fixed list owner, admin, manager, editor, member, viewer. Full access is always available and is not declared. A team member is given one app role per app."
|
|
19657
|
+
}),
|
|
19621
19658
|
tools: toolsSchema.meta({
|
|
19622
19659
|
description: "The MCP tools this app serves to AI assistants, published as `<slug>_<name>`. Each one a site manager accepts becomes callable on their behalf by an assistant."
|
|
19623
19660
|
}),
|
|
@@ -19974,6 +20011,7 @@ var appManifestSchema = baseSchema.superRefine((manifest, ctx) => {
|
|
|
19974
20011
|
validateOauth(manifest, ctx);
|
|
19975
20012
|
validateServer(manifest, ctx);
|
|
19976
20013
|
validateTools(manifest.tools, ctx);
|
|
20014
|
+
validateRoles(manifest, ctx);
|
|
19977
20015
|
});
|
|
19978
20016
|
|
|
19979
20017
|
// ../../../libs/app-manifest/src/oauth-flow.ts
|
|
@@ -20146,6 +20184,14 @@ var lifecycleEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
20146
20184
|
}).strict(),
|
|
20147
20185
|
external_exports.object({ ...lifecycleBase, type: external_exports.literal("uninstalled"), scope: external_exports.enum(["app", "install"]) }).strict()
|
|
20148
20186
|
]);
|
|
20187
|
+
var deleteRequestSchema = external_exports.object({
|
|
20188
|
+
eventId: external_exports.string().min(1).max(64),
|
|
20189
|
+
occurredAt: external_exports.number().int().nonnegative().safe(),
|
|
20190
|
+
install: installSchema2,
|
|
20191
|
+
personId: external_exports.string().min(1).nullable(),
|
|
20192
|
+
anonIds: external_exports.array(external_exports.string().min(1)),
|
|
20193
|
+
identifiers: external_exports.array(external_exports.object({ type: external_exports.enum(["email", "phone", "custom"]), value: external_exports.string().min(1) }).strict()).optional()
|
|
20194
|
+
}).strict();
|
|
20149
20195
|
var migrationSchema = external_exports.discriminatedUnion("phase", [
|
|
20150
20196
|
external_exports.object({
|
|
20151
20197
|
resource: external_exports.string().min(1).max(64),
|
|
@@ -20188,7 +20234,12 @@ var toolSchema2 = external_exports.object({
|
|
|
20188
20234
|
name: external_exports.string().min(1).max(MAX_APP_TOOL_NAME_LENGTH).regex(APP_TOOL_NAME_PATTERN),
|
|
20189
20235
|
// Who asked, and what they may do on this site. Derived from the bearer by the portal, never
|
|
20190
20236
|
// from the model's arguments.
|
|
20191
|
-
viewer: external_exports.object({
|
|
20237
|
+
viewer: external_exports.object({
|
|
20238
|
+
userId: external_exports.string().min(1).max(64),
|
|
20239
|
+
access: external_exports.enum(["read", "write"]),
|
|
20240
|
+
// Optional only while a site worker or app runtime that predates it can still receive this envelope; absent means `full`.
|
|
20241
|
+
appRole: external_exports.enum(APP_ROLES).optional()
|
|
20242
|
+
}).strict(),
|
|
20192
20243
|
// Already validated against the tool's declared inputSchema, with the reserved routing names
|
|
20193
20244
|
// stripped. Every declared input schema has an object root, so this is an object too — and a
|
|
20194
20245
|
// call that names no arguments normalizes to `{}` rather than reaching the handler as undefined.
|
|
@@ -20203,10 +20254,11 @@ var toolSchema2 = external_exports.object({
|
|
|
20203
20254
|
}, "Tool arguments exceed the size cap");
|
|
20204
20255
|
var controlEnvelopeSchema = external_exports.object({
|
|
20205
20256
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
20206
|
-
kind: external_exports.enum(["noop", "lifecycle", "migration", "schedule", "tool"]),
|
|
20257
|
+
kind: external_exports.enum(["noop", "lifecycle", "deleteRequest", "migration", "schedule", "tool"]),
|
|
20207
20258
|
app: external_exports.object({ slug: external_exports.string().min(1).max(30), version: external_exports.string().min(1).max(32) }).strict(),
|
|
20208
20259
|
install: 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().optional(),
|
|
20209
20260
|
lifecycle: lifecycleEventSchema.optional(),
|
|
20261
|
+
deleteRequest: deleteRequestSchema.optional(),
|
|
20210
20262
|
migration: migrationSchema.optional(),
|
|
20211
20263
|
schedule: scheduleSchema2.optional(),
|
|
20212
20264
|
tool: toolSchema2.optional()
|
|
@@ -20214,6 +20266,9 @@ var controlEnvelopeSchema = external_exports.object({
|
|
|
20214
20266
|
if (envelope.kind === "lifecycle" !== (envelope.lifecycle !== void 0)) {
|
|
20215
20267
|
ctx.addIssue({ code: "custom", path: ["lifecycle"], message: "Lifecycle payload must match the control kind" });
|
|
20216
20268
|
}
|
|
20269
|
+
if (envelope.kind === "deleteRequest" !== (envelope.deleteRequest !== void 0)) {
|
|
20270
|
+
ctx.addIssue({ code: "custom", path: ["deleteRequest"], message: "Delete request payload must match the control kind" });
|
|
20271
|
+
}
|
|
20217
20272
|
if (envelope.kind === "migration" !== (envelope.migration !== void 0)) {
|
|
20218
20273
|
ctx.addIssue({ code: "custom", path: ["migration"], message: "Migration payload must match the control kind" });
|
|
20219
20274
|
}
|
|
@@ -20223,8 +20278,8 @@ var controlEnvelopeSchema = external_exports.object({
|
|
|
20223
20278
|
if (envelope.kind === "tool" !== (envelope.tool !== void 0)) {
|
|
20224
20279
|
ctx.addIssue({ code: "custom", path: ["tool"], message: "Tool payload must match the control kind" });
|
|
20225
20280
|
}
|
|
20226
|
-
if (envelope.kind === "lifecycle" && envelope.install === void 0) {
|
|
20227
|
-
ctx.addIssue({ code: "custom", path: ["install"], message:
|
|
20281
|
+
if ((envelope.kind === "lifecycle" || envelope.kind === "deleteRequest") && envelope.install === void 0) {
|
|
20282
|
+
ctx.addIssue({ code: "custom", path: ["install"], message: `${envelope.kind} control needs an install` });
|
|
20228
20283
|
}
|
|
20229
20284
|
if (envelope.kind === "tool" && envelope.install === void 0) {
|
|
20230
20285
|
ctx.addIssue({ code: "custom", path: ["install"], message: "Tool control needs an install" });
|
|
@@ -20263,6 +20318,8 @@ var toolResultSchema = external_exports.object({
|
|
|
20263
20318
|
var controlResponseSchema = external_exports.object({
|
|
20264
20319
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
20265
20320
|
ok: external_exports.boolean(),
|
|
20321
|
+
// The bundle has no delete request handler, so a retry cannot succeed.
|
|
20322
|
+
skipped: external_exports.literal(true).optional(),
|
|
20266
20323
|
tool: toolResultSchema.optional(),
|
|
20267
20324
|
migration: external_exports.union([
|
|
20268
20325
|
external_exports.object({ done: external_exports.literal(true) }).strict(),
|
|
@@ -20416,7 +20473,12 @@ var appUiAnalyticsQueryPath = (domainId, appSlug2, resourceIdentifier) => {
|
|
|
20416
20473
|
var uiInstallSchema = external_exports.object({ id: external_exports.string().min(1).max(64), ord: external_exports.number().int().min(1), label: external_exports.string().max(100), enabled: external_exports.boolean() }).strict();
|
|
20417
20474
|
var uiContextSchema = external_exports.object({
|
|
20418
20475
|
version: external_exports.string().min(1).max(32),
|
|
20419
|
-
viewer: external_exports.object({
|
|
20476
|
+
viewer: external_exports.object({
|
|
20477
|
+
userId: external_exports.string().min(1).max(64),
|
|
20478
|
+
access: external_exports.enum(["read", "write"]),
|
|
20479
|
+
// Optional only while a site worker that predates it can still send this header; absent means `full`.
|
|
20480
|
+
appRole: external_exports.enum(APP_ROLES).optional()
|
|
20481
|
+
}).strict(),
|
|
20420
20482
|
install: uiInstallSchema,
|
|
20421
20483
|
installs: external_exports.array(uiInstallSchema).min(1).max(MAX_INSTALLS_PER_APP),
|
|
20422
20484
|
writeTicket: external_exports.string().min(1).max(2048).optional()
|
|
@@ -20435,6 +20497,21 @@ var parseUiContext = (raw) => {
|
|
|
20435
20497
|
return parsed.success ? parsed.data : null;
|
|
20436
20498
|
};
|
|
20437
20499
|
|
|
20500
|
+
// src/app-env.ts
|
|
20501
|
+
var PLATFORM_BINDINGS = new Set(
|
|
20502
|
+
PLATFORM_APP_BINDINGS.filter((name) => {
|
|
20503
|
+
return name !== PLATFORM_APP_BINDING_NAMES.installToken;
|
|
20504
|
+
})
|
|
20505
|
+
);
|
|
20506
|
+
var PLATFORM_PREFIXES = ["VAR_", "APPVAR_", PLATFORM_APP_OAUTH_BINDING_PREFIX];
|
|
20507
|
+
var appEnv = (env) => {
|
|
20508
|
+
return Object.fromEntries(
|
|
20509
|
+
Object.entries(env).filter(([name]) => {
|
|
20510
|
+
return !PLATFORM_BINDINGS.has(name) && !PLATFORM_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
20511
|
+
})
|
|
20512
|
+
);
|
|
20513
|
+
};
|
|
20514
|
+
|
|
20438
20515
|
// ../../../libs/tail-trace/src/validate.ts
|
|
20439
20516
|
var TRACE_ID = /^[0-9a-f]{32}$/;
|
|
20440
20517
|
var SPAN_ID = /^[0-9a-f]{16}$/;
|
|
@@ -21023,6 +21100,15 @@ var brokerIdentityRead = async (env, identifier, options = {}) => {
|
|
|
21023
21100
|
});
|
|
21024
21101
|
return { globalId: answer.globalId ?? null, anonIds: answer.anonIds ?? [], nextCursor: answer.nextCursor ?? null };
|
|
21025
21102
|
};
|
|
21103
|
+
var brokerCurrencyRates = async (env) => {
|
|
21104
|
+
const answer = await askBroker(env, "apps.currency rates", {
|
|
21105
|
+
v: ENVELOPE_VERSION,
|
|
21106
|
+
kind: "currencyRates",
|
|
21107
|
+
slug: callerSlug(env),
|
|
21108
|
+
key: env.QINTO_INTERNAL_KEY
|
|
21109
|
+
});
|
|
21110
|
+
return { rates: answer.rates, fetchedAt: answer.fetchedAt };
|
|
21111
|
+
};
|
|
21026
21112
|
var buildIdentity = (env) => {
|
|
21027
21113
|
return {
|
|
21028
21114
|
resolve: (identifier, options) => {
|
|
@@ -21561,7 +21647,7 @@ var buildWorkflowContext = (env, stamp) => {
|
|
|
21561
21647
|
depth: 0
|
|
21562
21648
|
});
|
|
21563
21649
|
return {
|
|
21564
|
-
env,
|
|
21650
|
+
env: appEnv(env),
|
|
21565
21651
|
install,
|
|
21566
21652
|
startWorkflow: buildStartWorkflow(stamp),
|
|
21567
21653
|
oauth: buildOauth(env, stamp.ord),
|
|
@@ -21634,12 +21720,13 @@ var buildContext = ({
|
|
|
21634
21720
|
emits,
|
|
21635
21721
|
pushes,
|
|
21636
21722
|
captures,
|
|
21637
|
-
context
|
|
21723
|
+
context,
|
|
21724
|
+
currency
|
|
21638
21725
|
}) => {
|
|
21639
21726
|
const { variables, secrets } = projectInstallValues(maps, kinds, install.ord);
|
|
21640
21727
|
const subject = envelope.user?.anonId ?? null;
|
|
21641
21728
|
return {
|
|
21642
|
-
env,
|
|
21729
|
+
env: appEnv(env),
|
|
21643
21730
|
site,
|
|
21644
21731
|
install: { id: install.id, label: install.label },
|
|
21645
21732
|
startWorkflow: buildStartWorkflow({
|
|
@@ -21703,10 +21790,45 @@ var buildContext = ({
|
|
|
21703
21790
|
},
|
|
21704
21791
|
observability: buildObservability(install.ord),
|
|
21705
21792
|
identity: buildIdentity(env),
|
|
21793
|
+
currency,
|
|
21706
21794
|
apps: buildAppsClient(env, envelope)
|
|
21707
21795
|
};
|
|
21708
21796
|
};
|
|
21709
21797
|
|
|
21798
|
+
// src/currency.ts
|
|
21799
|
+
var rateBetween = (rates, from, to) => {
|
|
21800
|
+
const source = from.trim().toUpperCase();
|
|
21801
|
+
const target = to.trim().toUpperCase();
|
|
21802
|
+
if (!Object.hasOwn(rates, source) || !Object.hasOwn(rates, target)) {
|
|
21803
|
+
return null;
|
|
21804
|
+
}
|
|
21805
|
+
return rates[source] / rates[target];
|
|
21806
|
+
};
|
|
21807
|
+
var buildCurrency = (env) => {
|
|
21808
|
+
let snapshot;
|
|
21809
|
+
const load = () => {
|
|
21810
|
+
snapshot ??= brokerCurrencyRates(env).catch((error61) => {
|
|
21811
|
+
throw new Error("the platform currency rates are not available", { cause: error61 });
|
|
21812
|
+
});
|
|
21813
|
+
return snapshot;
|
|
21814
|
+
};
|
|
21815
|
+
return {
|
|
21816
|
+
convert: async (amount, from, to) => {
|
|
21817
|
+
const rate = rateBetween((await load()).rates, from, to);
|
|
21818
|
+
return rate === null ? null : amount * rate;
|
|
21819
|
+
},
|
|
21820
|
+
rate: async (from, to) => {
|
|
21821
|
+
return rateBetween((await load()).rates, from, to);
|
|
21822
|
+
},
|
|
21823
|
+
list: async () => {
|
|
21824
|
+
return Object.keys((await load()).rates).sort();
|
|
21825
|
+
},
|
|
21826
|
+
updatedAt: async () => {
|
|
21827
|
+
return new Date((await load()).fetchedAt);
|
|
21828
|
+
}
|
|
21829
|
+
};
|
|
21830
|
+
};
|
|
21831
|
+
|
|
21710
21832
|
// src/install-span.ts
|
|
21711
21833
|
var installSpan = (install, run) => {
|
|
21712
21834
|
return traced(
|
|
@@ -21803,10 +21925,11 @@ var dispatchSchedule = async (envelope, bundle, env) => {
|
|
|
21803
21925
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
21804
21926
|
const event = { id: schedule.id, cron: schedule.cron, scheduledTime: new Date(schedule.scheduledTime) };
|
|
21805
21927
|
const failed = [];
|
|
21928
|
+
const currency = buildCurrency(env);
|
|
21806
21929
|
for (const install of schedule.installs) {
|
|
21807
21930
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
21808
21931
|
const context = {
|
|
21809
|
-
env,
|
|
21932
|
+
env: appEnv(env),
|
|
21810
21933
|
site,
|
|
21811
21934
|
install: { id: install.id, label: install.label },
|
|
21812
21935
|
startWorkflow: buildStartWorkflow({
|
|
@@ -21822,6 +21945,7 @@ var dispatchSchedule = async (envelope, bundle, env) => {
|
|
|
21822
21945
|
appSecrets: appScope.appSecrets,
|
|
21823
21946
|
observability: buildObservability(install.ord),
|
|
21824
21947
|
identity: buildIdentity(env),
|
|
21948
|
+
currency,
|
|
21825
21949
|
apps: buildAppsClient(env, { depth: 0 }),
|
|
21826
21950
|
query: buildQuery({ env, ticket: install.queryTicket, installId: install.id }),
|
|
21827
21951
|
push: async (userId, message) => {
|
|
@@ -21938,10 +22062,11 @@ var buildContext2 = (envelope, env) => {
|
|
|
21938
22062
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
21939
22063
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
21940
22064
|
return {
|
|
21941
|
-
env,
|
|
22065
|
+
env: appEnv(env),
|
|
21942
22066
|
site,
|
|
21943
22067
|
install: { id: install.id, label: install.label },
|
|
21944
|
-
|
|
22068
|
+
// An envelope from a portal that predates the role, or one carrying `full`, has no `appRole`.
|
|
22069
|
+
viewer: { ...envelope.tool.viewer, appRole: envelope.tool.viewer.appRole ?? "full" },
|
|
21945
22070
|
callId: envelope.tool.callId,
|
|
21946
22071
|
startWorkflow: buildStartWorkflow({ ord: install.ord, installId: install.id, installLabel: install.label, anonId: null }),
|
|
21947
22072
|
oauth: buildOauth(env, install.ord),
|
|
@@ -21951,6 +22076,7 @@ var buildContext2 = (envelope, env) => {
|
|
|
21951
22076
|
appSecrets: appScope.appSecrets,
|
|
21952
22077
|
observability: buildObservability(install.ord),
|
|
21953
22078
|
identity: buildIdentity(env),
|
|
22079
|
+
currency: buildCurrency(env),
|
|
21954
22080
|
apps: buildAppsClient(env, { depth: 0 }),
|
|
21955
22081
|
query: buildQuery({ env, ticket: envelope.tool.queryTicket, installId: install.id }),
|
|
21956
22082
|
track: async (userId, event) => {
|
|
@@ -22014,12 +22140,11 @@ var controlContextValues = (env) => {
|
|
|
22014
22140
|
appScope: projectAppValues(env, appVariableKinds)
|
|
22015
22141
|
};
|
|
22016
22142
|
};
|
|
22017
|
-
var lifecycleContext = (env,
|
|
22018
|
-
const install = envelope.install;
|
|
22143
|
+
var lifecycleContext = (env, install) => {
|
|
22019
22144
|
const { maps, variableKinds, site, appScope } = controlContextValues(env);
|
|
22020
22145
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
22021
22146
|
return {
|
|
22022
|
-
env,
|
|
22147
|
+
env: appEnv(env),
|
|
22023
22148
|
site,
|
|
22024
22149
|
install: { id: install.id, label: install.label },
|
|
22025
22150
|
variables,
|
|
@@ -22032,19 +22157,21 @@ var lifecycleContext = (env, envelope) => {
|
|
|
22032
22157
|
installLabel: install.label,
|
|
22033
22158
|
anonId: null
|
|
22034
22159
|
}),
|
|
22035
|
-
observability: buildObservability(install.ord)
|
|
22160
|
+
observability: buildObservability(install.ord),
|
|
22161
|
+
currency: buildCurrency(env)
|
|
22036
22162
|
};
|
|
22037
22163
|
};
|
|
22038
22164
|
var migrationContext = (env) => {
|
|
22039
22165
|
const { site, appScope } = controlContextValues(env);
|
|
22040
22166
|
return {
|
|
22041
|
-
env,
|
|
22167
|
+
env: appEnv(env),
|
|
22042
22168
|
site,
|
|
22043
22169
|
appVariables: appScope.appVariables,
|
|
22044
22170
|
appSecrets: appScope.appSecrets,
|
|
22045
22171
|
// A migration runs once for the site, not once per install, so it has no install to attribute
|
|
22046
22172
|
// an event or a saved error to.
|
|
22047
|
-
observability: buildObservability(null)
|
|
22173
|
+
observability: buildObservability(null),
|
|
22174
|
+
currency: buildCurrency(env)
|
|
22048
22175
|
};
|
|
22049
22176
|
};
|
|
22050
22177
|
var runStatementMigration = async (env, migration) => {
|
|
@@ -22065,22 +22192,43 @@ var runStatementMigration = async (env, migration) => {
|
|
|
22065
22192
|
const ledger = database.prepare("INSERT INTO _qinto_migrations (id, checksum, phase, applied_at) VALUES (?, ?, ?, ?)").bind(migration.id, migration.checksum, migration.phase, (/* @__PURE__ */ new Date()).toISOString());
|
|
22066
22193
|
await database.batch([...migration.statements.map((statement) => database.prepare(statement)), ledger]);
|
|
22067
22194
|
};
|
|
22068
|
-
var
|
|
22069
|
-
const event = envelope.lifecycle;
|
|
22070
|
-
const handler = bundle.onLifecycle?.[event.type];
|
|
22071
|
-
if (typeof handler !== "function") {
|
|
22072
|
-
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: true });
|
|
22073
|
-
}
|
|
22074
|
-
const install = envelope.install;
|
|
22195
|
+
var runInstallHook = async (install, run, env) => {
|
|
22075
22196
|
try {
|
|
22076
22197
|
await installSpan(install, () => {
|
|
22077
|
-
return
|
|
22198
|
+
return run(lifecycleContext(env, install));
|
|
22078
22199
|
});
|
|
22079
22200
|
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: true });
|
|
22080
22201
|
} catch (error61) {
|
|
22081
22202
|
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: false, error: { message: failureMessage(error61) } });
|
|
22082
22203
|
}
|
|
22083
22204
|
};
|
|
22205
|
+
var dispatchLifecycle = async (envelope, bundle, env) => {
|
|
22206
|
+
const event = envelope.lifecycle;
|
|
22207
|
+
const handler = bundle.onLifecycle?.[event.type];
|
|
22208
|
+
if (typeof handler !== "function") {
|
|
22209
|
+
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: true });
|
|
22210
|
+
}
|
|
22211
|
+
return runInstallHook(
|
|
22212
|
+
envelope.install,
|
|
22213
|
+
(context) => {
|
|
22214
|
+
return handler(event, context);
|
|
22215
|
+
},
|
|
22216
|
+
env
|
|
22217
|
+
);
|
|
22218
|
+
};
|
|
22219
|
+
var dispatchDeleteRequest = async (envelope, bundle, env) => {
|
|
22220
|
+
const handler = bundle.onDeleteRequest;
|
|
22221
|
+
if (typeof handler !== "function") {
|
|
22222
|
+
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: false, skipped: true });
|
|
22223
|
+
}
|
|
22224
|
+
return runInstallHook(
|
|
22225
|
+
envelope.install,
|
|
22226
|
+
(context) => {
|
|
22227
|
+
return handler(envelope.deleteRequest, context);
|
|
22228
|
+
},
|
|
22229
|
+
env
|
|
22230
|
+
);
|
|
22231
|
+
};
|
|
22084
22232
|
var dispatchMigration = async (envelope, bundle, env) => {
|
|
22085
22233
|
const migration = envelope.migration;
|
|
22086
22234
|
if (linkedDatabasesOf(env).includes(migration.resource)) {
|
|
@@ -22135,6 +22283,9 @@ var dispatchControl = async ({ request, env, versions }) => {
|
|
|
22135
22283
|
case "lifecycle": {
|
|
22136
22284
|
return dispatchLifecycle(envelope, bundle, env);
|
|
22137
22285
|
}
|
|
22286
|
+
case "deleteRequest": {
|
|
22287
|
+
return dispatchDeleteRequest(envelope, bundle, env);
|
|
22288
|
+
}
|
|
22138
22289
|
case "migration": {
|
|
22139
22290
|
return dispatchMigration(envelope, bundle, env);
|
|
22140
22291
|
}
|
|
@@ -22185,11 +22336,12 @@ var buildContext3 = ({
|
|
|
22185
22336
|
site,
|
|
22186
22337
|
geo,
|
|
22187
22338
|
params,
|
|
22188
|
-
user
|
|
22339
|
+
user,
|
|
22340
|
+
currency
|
|
22189
22341
|
}) => {
|
|
22190
22342
|
const { variables, secrets } = projectInstallValues(maps, kinds, install.ord);
|
|
22191
22343
|
return {
|
|
22192
|
-
env,
|
|
22344
|
+
env: appEnv(env),
|
|
22193
22345
|
site,
|
|
22194
22346
|
geo,
|
|
22195
22347
|
params,
|
|
@@ -22208,6 +22360,7 @@ var buildContext3 = ({
|
|
|
22208
22360
|
appSecrets: appScope.appSecrets,
|
|
22209
22361
|
observability: buildObservability(install.ord),
|
|
22210
22362
|
identity: buildIdentity(env),
|
|
22363
|
+
currency,
|
|
22211
22364
|
apps: buildAppsClient(env, { depth: 0 }),
|
|
22212
22365
|
push: async (userId, message) => {
|
|
22213
22366
|
await brokerPush(env, {
|
|
@@ -22300,6 +22453,7 @@ var dispatchEndpoint = async ({ request, env, versions }) => {
|
|
|
22300
22453
|
const maps = parseVariableMaps(env);
|
|
22301
22454
|
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
22302
22455
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22456
|
+
const currency = buildCurrency(env);
|
|
22303
22457
|
const invoke = async (install) => {
|
|
22304
22458
|
return installSpan(install, () => {
|
|
22305
22459
|
return handler(
|
|
@@ -22313,7 +22467,8 @@ var dispatchEndpoint = async ({ request, env, versions }) => {
|
|
|
22313
22467
|
site,
|
|
22314
22468
|
geo: context.geo,
|
|
22315
22469
|
params: context.params,
|
|
22316
|
-
user: context.user
|
|
22470
|
+
user: context.user,
|
|
22471
|
+
currency
|
|
22317
22472
|
})
|
|
22318
22473
|
);
|
|
22319
22474
|
});
|
|
@@ -22456,6 +22611,69 @@ var checkAgainst = async (schema, value) => {
|
|
|
22456
22611
|
return { ok: false, message };
|
|
22457
22612
|
};
|
|
22458
22613
|
|
|
22614
|
+
// src/rpc.ts
|
|
22615
|
+
var dispatchRpc = async (envelope, bundle, env) => {
|
|
22616
|
+
if (envelope.installs.length > 1) {
|
|
22617
|
+
return jsonError(400, "rpc envelope carries more than one install");
|
|
22618
|
+
}
|
|
22619
|
+
const rpc = envelope.rpc;
|
|
22620
|
+
if (rpc === void 0) {
|
|
22621
|
+
return jsonError(400, "rpc envelope carries no rpc call");
|
|
22622
|
+
}
|
|
22623
|
+
const definition = rpcDefinitionOf(bundle?.rpc?.[rpc.fn]);
|
|
22624
|
+
if (definition === void 0) {
|
|
22625
|
+
return jsonError(200, `missing handler: rpc.${rpc.fn}`);
|
|
22626
|
+
}
|
|
22627
|
+
const args = await checkAgainst(definition.input, rpc.args);
|
|
22628
|
+
if (!args.ok) {
|
|
22629
|
+
return json2(200, { v: ENVELOPE_VERSION, error: { code: "invalid_arguments", message: failureMessage(args.message) } });
|
|
22630
|
+
}
|
|
22631
|
+
const install = envelope.installs[0];
|
|
22632
|
+
const emits = [];
|
|
22633
|
+
const pushes = [];
|
|
22634
|
+
const captures = [];
|
|
22635
|
+
const context = contextCollector();
|
|
22636
|
+
const maps = parseVariableMaps(env);
|
|
22637
|
+
const { variableKinds: kinds, appVariableKinds, site } = appContextOf(env);
|
|
22638
|
+
const appScope = projectAppValues(env, appVariableKinds);
|
|
22639
|
+
const currency = buildCurrency(env);
|
|
22640
|
+
const subject = envelope.user?.anonId ?? null;
|
|
22641
|
+
const ctx = {
|
|
22642
|
+
...buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context, currency }),
|
|
22643
|
+
context: fetchedContext(
|
|
22644
|
+
env,
|
|
22645
|
+
(what) => {
|
|
22646
|
+
return requireSubject(subject, what);
|
|
22647
|
+
},
|
|
22648
|
+
context
|
|
22649
|
+
)
|
|
22650
|
+
};
|
|
22651
|
+
let value;
|
|
22652
|
+
try {
|
|
22653
|
+
value = await installSpan(install, () => {
|
|
22654
|
+
return definition.handler(args.value, ctx);
|
|
22655
|
+
});
|
|
22656
|
+
} catch (error61) {
|
|
22657
|
+
const message = failureMessage(error61);
|
|
22658
|
+
console.warn(`rpc failed for install ${install.id}: ${message}`);
|
|
22659
|
+
return json2(200, { v: ENVELOPE_VERSION, error: { message } });
|
|
22660
|
+
}
|
|
22661
|
+
const checked = await checkAgainst(definition.output, value);
|
|
22662
|
+
if (!checked.ok) {
|
|
22663
|
+
return jsonError(200, failureMessage(`rpc result does not match the output schema: ${checked.message}`));
|
|
22664
|
+
}
|
|
22665
|
+
const result = checked.value === void 0 ? null : checked.value;
|
|
22666
|
+
if (new TextEncoder().encode(JSON.stringify(result)).length > MAX_RPC_BYTES) {
|
|
22667
|
+
return jsonError(200, "rpc result exceeds the size cap");
|
|
22668
|
+
}
|
|
22669
|
+
const body = { v: ENVELOPE_VERSION, rpc: { result } };
|
|
22670
|
+
const contextWrites = context.writes();
|
|
22671
|
+
if (emits.length > 0 || pushes.length > 0 || captures.length > 0 || contextWrites.length > 0) {
|
|
22672
|
+
body.effects = [{ ord: install.ord, emits, pushes, captures, context: contextWrites }];
|
|
22673
|
+
}
|
|
22674
|
+
return json2(200, body);
|
|
22675
|
+
};
|
|
22676
|
+
|
|
22459
22677
|
// src/traced-fetch.ts
|
|
22460
22678
|
var MAX_BODY_CHARS = 65536;
|
|
22461
22679
|
var TOO_LARGE = `[not recorded: the body is over ${MAX_BODY_CHARS} characters]`;
|
|
@@ -22607,7 +22825,7 @@ var dispatchUi = async ({ request, env, versions }) => {
|
|
|
22607
22825
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, context.install.ord);
|
|
22608
22826
|
const { appVariables, appSecrets } = projectAppValues(env, appVariableKinds);
|
|
22609
22827
|
const ctx = {
|
|
22610
|
-
env,
|
|
22828
|
+
env: appEnv(env),
|
|
22611
22829
|
site,
|
|
22612
22830
|
install: { id: context.install.id, label: context.install.label },
|
|
22613
22831
|
installs: projectAllInstallValues(maps, variableKinds, context.installs),
|
|
@@ -22624,7 +22842,8 @@ var dispatchUi = async ({ request, env, versions }) => {
|
|
|
22624
22842
|
secrets,
|
|
22625
22843
|
appVariables,
|
|
22626
22844
|
appSecrets,
|
|
22627
|
-
|
|
22845
|
+
// A site worker that predates app roles sends none, and every member had full access then.
|
|
22846
|
+
viewer: { ...context.viewer, appRole: context.viewer.appRole ?? "full" },
|
|
22628
22847
|
observability: buildObservability(context.install.ord),
|
|
22629
22848
|
identity: buildIdentity(env),
|
|
22630
22849
|
apps: buildAppsClient(env, { depth: 0 })
|
|
@@ -22666,7 +22885,7 @@ var withAppDurableObject = (Base, migrations) => {
|
|
|
22666
22885
|
return class extends Base {
|
|
22667
22886
|
constructor(ctx, env) {
|
|
22668
22887
|
applyDurableObjectMigrations(ctx.storage, migrations);
|
|
22669
|
-
super(ctx, env);
|
|
22888
|
+
super(ctx, appEnv(env));
|
|
22670
22889
|
}
|
|
22671
22890
|
};
|
|
22672
22891
|
};
|
|
@@ -22692,12 +22911,13 @@ var runInstalls = async (envelope, env, invoke) => {
|
|
|
22692
22911
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22693
22912
|
const groups = [];
|
|
22694
22913
|
let failure2;
|
|
22914
|
+
const currency = buildCurrency(env);
|
|
22695
22915
|
for (const install of envelope.installs) {
|
|
22696
22916
|
const emits = [];
|
|
22697
22917
|
const pushes = [];
|
|
22698
22918
|
const captures = [];
|
|
22699
22919
|
const context = contextCollector();
|
|
22700
|
-
const ctx = buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context });
|
|
22920
|
+
const ctx = buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context, currency });
|
|
22701
22921
|
try {
|
|
22702
22922
|
await installSpan(install, () => {
|
|
22703
22923
|
return invoke(ctx, install);
|
|
@@ -22758,7 +22978,8 @@ var runTransform = async (envelope, env, action, handler) => {
|
|
|
22758
22978
|
emits,
|
|
22759
22979
|
pushes,
|
|
22760
22980
|
captures,
|
|
22761
|
-
context
|
|
22981
|
+
context,
|
|
22982
|
+
currency: buildCurrency(env)
|
|
22762
22983
|
});
|
|
22763
22984
|
const ctx = {
|
|
22764
22985
|
...withoutApps,
|
|
@@ -22810,66 +23031,6 @@ var dispatchTransform = async (envelope, bundle, env) => {
|
|
|
22810
23031
|
}
|
|
22811
23032
|
return runTransform(envelope, env, action, handler);
|
|
22812
23033
|
};
|
|
22813
|
-
var dispatchRpc = async (envelope, bundle, env) => {
|
|
22814
|
-
if (envelope.installs.length > 1) {
|
|
22815
|
-
return jsonError(400, "rpc envelope carries more than one install");
|
|
22816
|
-
}
|
|
22817
|
-
const rpc = envelope.rpc;
|
|
22818
|
-
if (rpc === void 0) {
|
|
22819
|
-
return jsonError(400, "rpc envelope carries no rpc call");
|
|
22820
|
-
}
|
|
22821
|
-
const definition = rpcDefinitionOf(bundle?.rpc?.[rpc.fn]);
|
|
22822
|
-
if (definition === void 0) {
|
|
22823
|
-
return jsonError(200, `missing handler: rpc.${rpc.fn}`);
|
|
22824
|
-
}
|
|
22825
|
-
const args = await checkAgainst(definition.input, rpc.args);
|
|
22826
|
-
if (!args.ok) {
|
|
22827
|
-
return json2(200, { v: ENVELOPE_VERSION, error: { code: "invalid_arguments", message: failureMessage(args.message) } });
|
|
22828
|
-
}
|
|
22829
|
-
const install = envelope.installs[0];
|
|
22830
|
-
const emits = [];
|
|
22831
|
-
const pushes = [];
|
|
22832
|
-
const captures = [];
|
|
22833
|
-
const context = contextCollector();
|
|
22834
|
-
const maps = parseVariableMaps(env);
|
|
22835
|
-
const { variableKinds: kinds, appVariableKinds, site } = appContextOf(env);
|
|
22836
|
-
const appScope = projectAppValues(env, appVariableKinds);
|
|
22837
|
-
const subject = envelope.user?.anonId ?? null;
|
|
22838
|
-
const ctx = {
|
|
22839
|
-
...buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context }),
|
|
22840
|
-
context: fetchedContext(
|
|
22841
|
-
env,
|
|
22842
|
-
(what) => {
|
|
22843
|
-
return requireSubject(subject, what);
|
|
22844
|
-
},
|
|
22845
|
-
context
|
|
22846
|
-
)
|
|
22847
|
-
};
|
|
22848
|
-
let value;
|
|
22849
|
-
try {
|
|
22850
|
-
value = await installSpan(install, () => {
|
|
22851
|
-
return definition.handler(args.value, ctx);
|
|
22852
|
-
});
|
|
22853
|
-
} catch (error61) {
|
|
22854
|
-
const message = failureMessage(error61);
|
|
22855
|
-
console.warn(`rpc failed for install ${install.id}: ${message}`);
|
|
22856
|
-
return json2(200, { v: ENVELOPE_VERSION, error: { message } });
|
|
22857
|
-
}
|
|
22858
|
-
const checked = await checkAgainst(definition.output, value);
|
|
22859
|
-
if (!checked.ok) {
|
|
22860
|
-
return jsonError(200, failureMessage(`rpc result does not match the output schema: ${checked.message}`));
|
|
22861
|
-
}
|
|
22862
|
-
const result = checked.value === void 0 ? null : checked.value;
|
|
22863
|
-
if (new TextEncoder().encode(JSON.stringify(result)).length > MAX_RPC_BYTES) {
|
|
22864
|
-
return jsonError(200, "rpc result exceeds the size cap");
|
|
22865
|
-
}
|
|
22866
|
-
const body = { v: ENVELOPE_VERSION, rpc: { result } };
|
|
22867
|
-
const contextWrites = context.writes();
|
|
22868
|
-
if (emits.length > 0 || pushes.length > 0 || captures.length > 0 || contextWrites.length > 0) {
|
|
22869
|
-
body.effects = [{ ord: install.ord, emits, pushes, captures, context: contextWrites }];
|
|
22870
|
-
}
|
|
22871
|
-
return json2(200, body);
|
|
22872
|
-
};
|
|
22873
23034
|
var dispatch = async (envelope, versions, env) => {
|
|
22874
23035
|
if (!(envelope.app.version in versions)) {
|
|
22875
23036
|
return jsonError(200, "unknown version");
|