@blotout/qinto-cli 0.1.16 → 0.1.18
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 +27 -8
- package/dist/index.js +3896 -3246
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +187 -61
- package/dist/worker-artifact/main/index.js +5596 -3957
- package/dist/worker-artifact/proxy/index.js +22410 -0
- package/dist/worker-artifact/proxy-wfp/index.js +1311 -0
- package/dist/worker-artifact/version.json +41 -5
- package/package.json +6 -6
- package/templates/project/package.json +2 -1
- package/templates/project/tsconfig.json +1 -1
|
@@ -18115,10 +18115,10 @@ var stringbool = (...args) => _stringbool({
|
|
|
18115
18115
|
String: ZodString
|
|
18116
18116
|
}, ...args);
|
|
18117
18117
|
function json(params) {
|
|
18118
|
-
const
|
|
18119
|
-
return union([string2(params), number2(), boolean2(), _null3(), array(
|
|
18118
|
+
const jsonSchema2 = lazy(() => {
|
|
18119
|
+
return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema2), record(string2(), jsonSchema2)]);
|
|
18120
18120
|
});
|
|
18121
|
-
return
|
|
18121
|
+
return jsonSchema2;
|
|
18122
18122
|
}
|
|
18123
18123
|
function preprocess(fn, schema) {
|
|
18124
18124
|
return new ZodPreprocess({
|
|
@@ -18945,6 +18945,7 @@ function date4(params) {
|
|
|
18945
18945
|
var IDENTIFIER = /^[a-z][a-z0-9-]*$/;
|
|
18946
18946
|
var VARIABLE_NAME = /^[A-Z][A-Z0-9_]*$/;
|
|
18947
18947
|
var APP_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,29}$/;
|
|
18948
|
+
var FUNCTION_NAME = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
18948
18949
|
var identifierField = external_exports.string().min(1).max(64).regex(IDENTIFIER);
|
|
18949
18950
|
var httpsUrl = (field2) => {
|
|
18950
18951
|
return external_exports.url().max(2048).refine((value) => value.startsWith("https://"), `${field2} must be an HTTPS URL`);
|
|
@@ -18958,6 +18959,10 @@ var uniqueOrIssue = (ctx, values, path, label) => {
|
|
|
18958
18959
|
seen.add(value);
|
|
18959
18960
|
}
|
|
18960
18961
|
};
|
|
18962
|
+
var PLATFORM_ZONES = ["blotout.io", "qinto.tech"];
|
|
18963
|
+
var isPlatformHost = (host) => {
|
|
18964
|
+
return PLATFORM_ZONES.some((zone) => host === zone || host.endsWith(`.${zone}`));
|
|
18965
|
+
};
|
|
18961
18966
|
|
|
18962
18967
|
// ../../../libs/app-manifest/src/oauth.ts
|
|
18963
18968
|
var OAUTH_TOKEN_METHODS = ["POST", "GET"];
|
|
@@ -18987,8 +18992,7 @@ var RESERVED_AUTHORIZE_PARAMS = /* @__PURE__ */ new Set([
|
|
|
18987
18992
|
var PRIVATE_HOST = /^(localhost|\[?::1\]?|.+\.local|.+\.internal|10\..+|127\..+|169\.254\..+|192\.168\..+|172\.(1[6-9]|2\d|3[01])\..+|\d+\.\d+\.\d+\.\d+)$/;
|
|
18988
18993
|
var vendorUrl = (field2) => {
|
|
18989
18994
|
return httpsUrl(field2).refine((value) => {
|
|
18990
|
-
|
|
18991
|
-
return host !== "qinto.io" && !host.endsWith(".qinto.io") && host !== "qinto.tech" && !host.endsWith(".qinto.tech");
|
|
18995
|
+
return !isPlatformHost(new URL(value).hostname);
|
|
18992
18996
|
}, `${field2} must be the vendor's own endpoint, not a Qinto platform URL`).refine((value) => {
|
|
18993
18997
|
return !PRIVATE_HOST.test(new URL(value).hostname);
|
|
18994
18998
|
}, `${field2} must be a public host`).refine((value) => {
|
|
@@ -19345,7 +19349,6 @@ var MAX_MANIFEST_MIGRATION_BYTES = 1024 * 1024;
|
|
|
19345
19349
|
var BINDING_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
19346
19350
|
var CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
19347
19351
|
var MIGRATION_ID = /^[a-z0-9][a-z0-9-]*$/;
|
|
19348
|
-
var FUNCTION_NAME = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
19349
19352
|
var EVENT_TOPIC = /^[a-z][a-z0-9:_-]*$/;
|
|
19350
19353
|
var QUERY_PARAM_NAME = /^[A-Za-z0-9_.-]+$/;
|
|
19351
19354
|
var COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
@@ -19383,10 +19386,10 @@ var PLATFORM_APP_RESOURCE_IDENTIFIERS = {
|
|
|
19383
19386
|
};
|
|
19384
19387
|
var PLATFORM_APP_VARIABLE_IDENTIFIER_PREFIX = "var-";
|
|
19385
19388
|
var PLATFORM_APP_SCOPE_VARIABLE_IDENTIFIER_PREFIX = "appvar-";
|
|
19389
|
+
var STORAGE_LINK_BINDING_PREFIX = "QINTO_LINK_";
|
|
19386
19390
|
var legalUrl = (field2) => {
|
|
19387
19391
|
return httpsUrl(field2).refine((value) => {
|
|
19388
|
-
|
|
19389
|
-
return host !== "qinto.io" && !host.endsWith(".qinto.io");
|
|
19392
|
+
return !isPlatformHost(new URL(value).hostname);
|
|
19390
19393
|
}, `${field2} must be the developer's own document, not a Qinto platform URL`);
|
|
19391
19394
|
};
|
|
19392
19395
|
var bindingField = external_exports.string().min(1).max(255).regex(BINDING_NAME);
|
|
@@ -19559,7 +19562,7 @@ var captureSchema = external_exports.object({
|
|
|
19559
19562
|
var endpointSchema = external_exports.object({
|
|
19560
19563
|
path: external_exports.string().min(1).max(255).regex(ENDPOINT_PATH_PATTERN, "Endpoint paths are absolute; each segment is a literal or a :name parameter"),
|
|
19561
19564
|
methods: external_exports.array(external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE"])).min(1).max(5),
|
|
19562
|
-
auth: external_exports.enum(["public", "token"]),
|
|
19565
|
+
auth: external_exports.enum(["public", "token", "visitor"]),
|
|
19563
19566
|
mode: external_exports.enum(["webhook", "api"])
|
|
19564
19567
|
}).strict();
|
|
19565
19568
|
var eventsSchema = external_exports.object({
|
|
@@ -19653,7 +19656,7 @@ var validateBindings = (manifest, ctx) => {
|
|
|
19653
19656
|
"variable name"
|
|
19654
19657
|
);
|
|
19655
19658
|
for (const [index, resource] of manifest.resources.entries()) {
|
|
19656
|
-
if (reserved.has(resource.binding) || resource.binding.startsWith("VAR_") || resource.binding.startsWith("APPVAR_") || resource.binding.startsWith(PLATFORM_APP_OAUTH_BINDING_PREFIX)) {
|
|
19659
|
+
if (reserved.has(resource.binding) || resource.binding.startsWith("VAR_") || resource.binding.startsWith("APPVAR_") || resource.binding.startsWith(PLATFORM_APP_OAUTH_BINDING_PREFIX) || resource.binding.startsWith(STORAGE_LINK_BINDING_PREFIX)) {
|
|
19657
19660
|
ctx.addIssue({ code: "custom", path: ["resources", index, "binding"], message: `Binding ${resource.binding} is reserved` });
|
|
19658
19661
|
}
|
|
19659
19662
|
if (reservedIdentifiers.has(resource.identifier) || resource.identifier.startsWith(PLATFORM_APP_VARIABLE_IDENTIFIER_PREFIX) || resource.identifier.startsWith(PLATFORM_APP_SCOPE_VARIABLE_IDENTIFIER_PREFIX)) {
|
|
@@ -19785,6 +19788,22 @@ var validatePipelines = (manifest, ctx) => {
|
|
|
19785
19788
|
}
|
|
19786
19789
|
}
|
|
19787
19790
|
};
|
|
19791
|
+
var validateVisitorEndpoint = (manifest, ctx, endpoint, index) => {
|
|
19792
|
+
if (endpoint.mode !== "api") {
|
|
19793
|
+
ctx.addIssue({
|
|
19794
|
+
code: "custom",
|
|
19795
|
+
path: ["endpoints", index, "mode"],
|
|
19796
|
+
message: "A visitor endpoint answers one visitor, so its mode must be api"
|
|
19797
|
+
});
|
|
19798
|
+
}
|
|
19799
|
+
if (manifest.browser?.entry === void 0) {
|
|
19800
|
+
ctx.addIssue({
|
|
19801
|
+
code: "custom",
|
|
19802
|
+
path: ["endpoints", index, "auth"],
|
|
19803
|
+
message: "A visitor endpoint is called by the app's own browser code, so it needs a browser entry"
|
|
19804
|
+
});
|
|
19805
|
+
}
|
|
19806
|
+
};
|
|
19788
19807
|
var validateEndpoints = (manifest, ctx) => {
|
|
19789
19808
|
const shapes = /* @__PURE__ */ new Map();
|
|
19790
19809
|
for (const [index, endpoint] of manifest.endpoints.entries()) {
|
|
@@ -19810,7 +19829,9 @@ var validateEndpoints = (manifest, ctx) => {
|
|
|
19810
19829
|
message: `Endpoint path ${endpoint.path} names the parameter ${repeated} twice`
|
|
19811
19830
|
});
|
|
19812
19831
|
}
|
|
19813
|
-
if (endpoint.
|
|
19832
|
+
if (endpoint.auth === "visitor") {
|
|
19833
|
+
validateVisitorEndpoint(manifest, ctx, endpoint, index);
|
|
19834
|
+
} else if (endpoint.mode === "api" && manifest.install.multiple) {
|
|
19814
19835
|
ctx.addIssue({
|
|
19815
19836
|
code: "custom",
|
|
19816
19837
|
path: ["endpoints", index, "mode"],
|
|
@@ -19956,8 +19977,17 @@ var appManifestSchema = baseSchema.superRefine((manifest, ctx) => {
|
|
|
19956
19977
|
var MAX_VENDOR_BODY_BYTES = 64 * 1024;
|
|
19957
19978
|
var MAX_EXPIRES_IN_SECONDS = 365 * 24 * 60 * 60;
|
|
19958
19979
|
|
|
19980
|
+
// ../../../libs/app-manifest/src/rpc-contract.ts
|
|
19981
|
+
var MAX_RPC_CONTRACT_BYTES = 256 * 1024;
|
|
19982
|
+
var jsonSchema = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
19983
|
+
var rpcFunctionContractSchema = external_exports.object({ visibility: external_exports.enum(["public", "private"]), input: jsonSchema, output: jsonSchema }).strict();
|
|
19984
|
+
var appRpcContractSchema = external_exports.record(external_exports.string().regex(FUNCTION_NAME).max(64), rpcFunctionContractSchema).refine((contract) => Object.keys(contract).length <= 32, "An RPC contract carries at most 32 functions").refine((contract) => {
|
|
19985
|
+
return new TextEncoder().encode(JSON.stringify(contract)).length <= MAX_RPC_CONTRACT_BYTES;
|
|
19986
|
+
}, "The RPC contract exceeds the size cap");
|
|
19987
|
+
|
|
19959
19988
|
// ../../../libs/app-envelope/src/envelope.ts
|
|
19960
|
-
var ENVELOPE_VERSION =
|
|
19989
|
+
var ENVELOPE_VERSION = 3;
|
|
19990
|
+
var ENVELOPE_ERROR_CODES = ["invalid_arguments"];
|
|
19961
19991
|
var MAX_INSTALLS_PER_APP = 15;
|
|
19962
19992
|
var MAX_EMITS_PER_INSTALL = 10;
|
|
19963
19993
|
var MAX_PUSHES_PER_INSTALL = 10;
|
|
@@ -20011,12 +20041,12 @@ var actionContextSchema = external_exports.discriminatedUnion("source", [
|
|
|
20011
20041
|
var envelopeRequestSchema = external_exports.object({
|
|
20012
20042
|
v: external_exports.literal(ENVELOPE_VERSION),
|
|
20013
20043
|
kind: external_exports.enum(["event", "connect", "transform", "rpc"]),
|
|
20014
|
-
site: external_exports.object({ origin: external_exports.string().min(1).max(255) }).strict(),
|
|
20015
20044
|
app: external_exports.object({ slug: external_exports.string().min(1).max(30), version: external_exports.string().min(1).max(32) }).strict(),
|
|
20016
20045
|
installs: external_exports.array(installSchema).min(1).max(MAX_INSTALLS_PER_APP),
|
|
20017
20046
|
user: external_exports.object({
|
|
20018
20047
|
anonId: external_exports.string().min(1).max(64),
|
|
20019
20048
|
globalId: external_exports.string().min(1).max(64).nullable(),
|
|
20049
|
+
createdAt: external_exports.number().int().optional(),
|
|
20020
20050
|
properties: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
20021
20051
|
geo: external_exports.record(external_exports.string(), external_exports.string()).optional()
|
|
20022
20052
|
}).strict().optional(),
|
|
@@ -20056,13 +20086,14 @@ var envelopeResponseSchema = external_exports.object({
|
|
|
20056
20086
|
rpc: external_exports.object({ result: external_exports.unknown() }).strict().refine((rpc) => {
|
|
20057
20087
|
return new TextEncoder().encode(JSON.stringify(rpc.result ?? null)).length <= MAX_RPC_BYTES;
|
|
20058
20088
|
}, "RPC result exceeds the size cap").optional(),
|
|
20059
|
-
error: external_exports.object({ message: external_exports.string().max(2048) }).strict().optional()
|
|
20089
|
+
error: external_exports.object({ message: external_exports.string().max(2048), code: external_exports.enum(ENVELOPE_ERROR_CODES).optional() }).strict().optional()
|
|
20060
20090
|
}).strict();
|
|
20061
20091
|
|
|
20062
20092
|
// ../../../libs/app-envelope/src/control.ts
|
|
20063
|
-
var CONTROL_ENVELOPE_VERSION =
|
|
20093
|
+
var CONTROL_ENVELOPE_VERSION = 2;
|
|
20064
20094
|
var MAX_CONTROL_BYTES = 256 * 1024;
|
|
20065
20095
|
var MAX_MIGRATION_CHECKPOINT_BYTES = 16 * 1024;
|
|
20096
|
+
var MIGRATION_DATABASE_LINK_CHANGED = "migration_database_link_changed";
|
|
20066
20097
|
var MAX_TOOL_ARGUMENTS_BYTES = 32 * 1024;
|
|
20067
20098
|
var MAX_TOOL_RESULT_BYTES = 64 * 1024;
|
|
20068
20099
|
var MAX_TOOL_DATA_DEPTH = 8;
|
|
@@ -20163,7 +20194,6 @@ var toolSchema2 = external_exports.object({
|
|
|
20163
20194
|
var controlEnvelopeSchema = external_exports.object({
|
|
20164
20195
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
20165
20196
|
kind: external_exports.enum(["noop", "lifecycle", "migration", "schedule", "tool"]),
|
|
20166
|
-
site: external_exports.object({ origin: external_exports.string().min(1).max(255) }).strict(),
|
|
20167
20197
|
app: external_exports.object({ slug: external_exports.string().min(1).max(30), version: external_exports.string().min(1).max(32) }).strict(),
|
|
20168
20198
|
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(),
|
|
20169
20199
|
lifecycle: lifecycleEventSchema.optional(),
|
|
@@ -20237,6 +20267,7 @@ var controlResponseSchema = external_exports.object({
|
|
|
20237
20267
|
var ENDPOINT_CONTEXT_HEADER = "x-qinto-endpoint-context";
|
|
20238
20268
|
var ENDPOINT_OUTCOMES_HEADER = "x-qinto-endpoint-outcomes";
|
|
20239
20269
|
var MAX_ENDPOINT_BODY_BYTES = 1024 * 1024;
|
|
20270
|
+
var MAX_VISITOR_ENDPOINT_BODY_BYTES = 2 * 1024 * 1024;
|
|
20240
20271
|
var MAX_ENDPOINT_OUTCOMES_BYTES = 64 * 1024;
|
|
20241
20272
|
var MAX_ENDPOINT_PATH_LENGTH = 16 * 1024;
|
|
20242
20273
|
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();
|
|
@@ -20252,12 +20283,14 @@ var endpointContextSchema = external_exports.object({
|
|
|
20252
20283
|
method: external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
20253
20284
|
mode: external_exports.enum(["webhook", "api"]),
|
|
20254
20285
|
version: external_exports.string().min(1).max(32),
|
|
20255
|
-
site: external_exports.object({ origin: external_exports.string().min(1).max(255) }).strict(),
|
|
20256
20286
|
geo: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
20257
|
-
installs: external_exports.array(installSchema3).min(1).max(15)
|
|
20287
|
+
installs: external_exports.array(installSchema3).min(1).max(15),
|
|
20288
|
+
user: external_exports.object({ anonId: external_exports.string().min(1).max(64) }).strict().optional()
|
|
20258
20289
|
}).strict().refine((context) => {
|
|
20259
20290
|
return context.mode === "webhook" || context.installs.length === 1;
|
|
20260
|
-
}, "An api endpoint carries exactly one install")
|
|
20291
|
+
}, "An api endpoint carries exactly one install").refine((context) => {
|
|
20292
|
+
return context.user === void 0 || context.mode === "api";
|
|
20293
|
+
}, "Only an api endpoint carries a visitor");
|
|
20261
20294
|
var endpointOutcomesSchema = external_exports.object({
|
|
20262
20295
|
outcomes: external_exports.array(
|
|
20263
20296
|
external_exports.object({
|
|
@@ -20868,6 +20901,10 @@ var siteChannel = (env) => {
|
|
|
20868
20901
|
var channelFetch = (env, init) => {
|
|
20869
20902
|
return siteChannel(env).fetch(BROKER_URL, init);
|
|
20870
20903
|
};
|
|
20904
|
+
var brokerFailure = (answer, status) => {
|
|
20905
|
+
const error61 = answer.error ?? `the broker answered ${status}`;
|
|
20906
|
+
return answer.message === void 0 ? error61 : `${error61}: ${answer.message}`;
|
|
20907
|
+
};
|
|
20871
20908
|
var askBroker = async (env, name, body) => {
|
|
20872
20909
|
return traced(name, {}, async () => {
|
|
20873
20910
|
const headers = { "content-type": "application/json" };
|
|
@@ -20891,7 +20928,7 @@ var askBroker = async (env, name, body) => {
|
|
|
20891
20928
|
}
|
|
20892
20929
|
const answer = parsed;
|
|
20893
20930
|
if (answer.error !== void 0 || !response.ok) {
|
|
20894
|
-
throw new Error(answer
|
|
20931
|
+
throw new Error(brokerFailure(answer, response.status));
|
|
20895
20932
|
}
|
|
20896
20933
|
return answer;
|
|
20897
20934
|
});
|
|
@@ -21269,9 +21306,13 @@ var parseVariableMaps = (env) => {
|
|
|
21269
21306
|
}
|
|
21270
21307
|
return maps;
|
|
21271
21308
|
};
|
|
21272
|
-
var
|
|
21309
|
+
var appContextOf = (env) => {
|
|
21310
|
+
const context = JSON.parse(env.APP_CONTEXT);
|
|
21311
|
+
return { variableKinds: context.variableKinds ?? {}, appVariableKinds: context.appVariableKinds ?? {}, site: context.site };
|
|
21312
|
+
};
|
|
21313
|
+
var linkedDatabasesOf = (env) => {
|
|
21273
21314
|
const context = JSON.parse(env.APP_CONTEXT);
|
|
21274
|
-
return
|
|
21315
|
+
return context.linkedDatabases ?? [];
|
|
21275
21316
|
};
|
|
21276
21317
|
var projectAppValues = (env, kinds) => {
|
|
21277
21318
|
const appVariables = {};
|
|
@@ -21290,7 +21331,7 @@ var projectAppValues = (env, kinds) => {
|
|
|
21290
21331
|
return { appVariables, appSecrets };
|
|
21291
21332
|
};
|
|
21292
21333
|
var secretValues = (env) => {
|
|
21293
|
-
const { variableKinds, appVariableKinds } =
|
|
21334
|
+
const { variableKinds, appVariableKinds } = appContextOf(env);
|
|
21294
21335
|
const values = /* @__PURE__ */ new Set();
|
|
21295
21336
|
for (const [name, byOrd] of parseVariableMaps(env)) {
|
|
21296
21337
|
if (variableKinds[name] !== "secret") {
|
|
@@ -21477,7 +21518,7 @@ var readStamp = (payload) => {
|
|
|
21477
21518
|
return { q: stamp, payload: params?.payload };
|
|
21478
21519
|
};
|
|
21479
21520
|
var buildWorkflowContext = (env, stamp) => {
|
|
21480
|
-
const { variableKinds, appVariableKinds } =
|
|
21521
|
+
const { variableKinds, appVariableKinds } = appContextOf(env);
|
|
21481
21522
|
const { variables, secrets } = projectInstallValues(parseVariableMaps(env), variableKinds, stamp.ord);
|
|
21482
21523
|
const { appVariables, appSecrets } = projectAppValues(env, appVariableKinds);
|
|
21483
21524
|
const install = { id: stamp.installId, label: stamp.installLabel };
|
|
@@ -21548,6 +21589,7 @@ var createWorkflow = (className, bundle) => {
|
|
|
21548
21589
|
var buildContext = ({
|
|
21549
21590
|
env,
|
|
21550
21591
|
envelope,
|
|
21592
|
+
site,
|
|
21551
21593
|
install,
|
|
21552
21594
|
maps,
|
|
21553
21595
|
kinds,
|
|
@@ -21561,7 +21603,7 @@ var buildContext = ({
|
|
|
21561
21603
|
const subject = envelope.user?.anonId ?? null;
|
|
21562
21604
|
return {
|
|
21563
21605
|
env,
|
|
21564
|
-
site
|
|
21606
|
+
site,
|
|
21565
21607
|
install: { id: install.id, label: install.label },
|
|
21566
21608
|
startWorkflow: buildStartWorkflow({
|
|
21567
21609
|
ord: install.ord,
|
|
@@ -21725,7 +21767,7 @@ var dispatchSchedule = async (envelope, bundle, env) => {
|
|
|
21725
21767
|
error: { message: `missing handler: schedules.${schedule.id}` }
|
|
21726
21768
|
});
|
|
21727
21769
|
}
|
|
21728
|
-
const { variableKinds, appVariableKinds } =
|
|
21770
|
+
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
21729
21771
|
const maps = parseVariableMaps(env);
|
|
21730
21772
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
21731
21773
|
const event = { id: schedule.id, cron: schedule.cron, scheduledTime: new Date(schedule.scheduledTime) };
|
|
@@ -21734,7 +21776,7 @@ var dispatchSchedule = async (envelope, bundle, env) => {
|
|
|
21734
21776
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
21735
21777
|
const context = {
|
|
21736
21778
|
env,
|
|
21737
|
-
site
|
|
21779
|
+
site,
|
|
21738
21780
|
install: { id: install.id, label: install.label },
|
|
21739
21781
|
startWorkflow: buildStartWorkflow({
|
|
21740
21782
|
ord: install.ord,
|
|
@@ -21759,6 +21801,11 @@ var dispatchSchedule = async (envelope, bundle, env) => {
|
|
|
21759
21801
|
data: message.data,
|
|
21760
21802
|
broadcast: message.broadcast
|
|
21761
21803
|
});
|
|
21804
|
+
},
|
|
21805
|
+
context: (userId) => {
|
|
21806
|
+
return asyncContext(env, () => {
|
|
21807
|
+
return userId;
|
|
21808
|
+
});
|
|
21762
21809
|
}
|
|
21763
21810
|
};
|
|
21764
21811
|
try {
|
|
@@ -21852,13 +21899,13 @@ var checkResult = (result) => {
|
|
|
21852
21899
|
};
|
|
21853
21900
|
var buildContext2 = (envelope, env) => {
|
|
21854
21901
|
const install = envelope.install;
|
|
21855
|
-
const { variableKinds, appVariableKinds } =
|
|
21902
|
+
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
21856
21903
|
const maps = parseVariableMaps(env);
|
|
21857
21904
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
21858
21905
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
21859
21906
|
return {
|
|
21860
21907
|
env,
|
|
21861
|
-
site
|
|
21908
|
+
site,
|
|
21862
21909
|
install: { id: install.id, label: install.label },
|
|
21863
21910
|
viewer: envelope.tool.viewer,
|
|
21864
21911
|
callId: envelope.tool.callId,
|
|
@@ -21922,20 +21969,21 @@ var controlError = (status, message) => {
|
|
|
21922
21969
|
return json2(status, { v: CONTROL_ENVELOPE_VERSION, ok: false, error: { message } });
|
|
21923
21970
|
};
|
|
21924
21971
|
var controlContextValues = (env) => {
|
|
21925
|
-
const { variableKinds, appVariableKinds } =
|
|
21972
|
+
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
21926
21973
|
return {
|
|
21927
21974
|
maps: parseVariableMaps(env),
|
|
21928
21975
|
variableKinds,
|
|
21976
|
+
site,
|
|
21929
21977
|
appScope: projectAppValues(env, appVariableKinds)
|
|
21930
21978
|
};
|
|
21931
21979
|
};
|
|
21932
21980
|
var lifecycleContext = (env, envelope) => {
|
|
21933
21981
|
const install = envelope.install;
|
|
21934
|
-
const { maps, variableKinds, appScope } = controlContextValues(env);
|
|
21982
|
+
const { maps, variableKinds, site, appScope } = controlContextValues(env);
|
|
21935
21983
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, install.ord);
|
|
21936
21984
|
return {
|
|
21937
21985
|
env,
|
|
21938
|
-
site
|
|
21986
|
+
site,
|
|
21939
21987
|
install: { id: install.id, label: install.label },
|
|
21940
21988
|
variables,
|
|
21941
21989
|
secrets,
|
|
@@ -21950,11 +21998,11 @@ var lifecycleContext = (env, envelope) => {
|
|
|
21950
21998
|
observability: buildObservability(install.ord)
|
|
21951
21999
|
};
|
|
21952
22000
|
};
|
|
21953
|
-
var migrationContext = (env
|
|
21954
|
-
const { appScope } = controlContextValues(env);
|
|
22001
|
+
var migrationContext = (env) => {
|
|
22002
|
+
const { site, appScope } = controlContextValues(env);
|
|
21955
22003
|
return {
|
|
21956
22004
|
env,
|
|
21957
|
-
site
|
|
22005
|
+
site,
|
|
21958
22006
|
appVariables: appScope.appVariables,
|
|
21959
22007
|
appSecrets: appScope.appSecrets,
|
|
21960
22008
|
// A migration runs once for the site, not once per install, so it has no install to attribute
|
|
@@ -21998,6 +22046,9 @@ var dispatchLifecycle = async (envelope, bundle, env) => {
|
|
|
21998
22046
|
};
|
|
21999
22047
|
var dispatchMigration = async (envelope, bundle, env) => {
|
|
22000
22048
|
const migration = envelope.migration;
|
|
22049
|
+
if (linkedDatabasesOf(env).includes(migration.resource)) {
|
|
22050
|
+
return json2(200, { v: CONTROL_ENVELOPE_VERSION, ok: false, error: { message: MIGRATION_DATABASE_LINK_CHANGED } });
|
|
22051
|
+
}
|
|
22001
22052
|
try {
|
|
22002
22053
|
if (migration.phase !== "backfill") {
|
|
22003
22054
|
await runStatementMigration(env, migration);
|
|
@@ -22007,10 +22058,7 @@ var dispatchMigration = async (envelope, bundle, env) => {
|
|
|
22007
22058
|
if (typeof handler !== "function") {
|
|
22008
22059
|
throw new Error(`missing migration handler: ${migration.handler}`);
|
|
22009
22060
|
}
|
|
22010
|
-
const result = await handler(
|
|
22011
|
-
{ id: migration.id, checkpoint: migration.checkpoint },
|
|
22012
|
-
migrationContext(env, envelope)
|
|
22013
|
-
);
|
|
22061
|
+
const result = await handler({ id: migration.id, checkpoint: migration.checkpoint }, migrationContext(env));
|
|
22014
22062
|
if (result.done !== true && result.done !== false) {
|
|
22015
22063
|
throw new Error("migration handler returned no completion result");
|
|
22016
22064
|
}
|
|
@@ -22099,7 +22147,8 @@ var buildContext3 = ({
|
|
|
22099
22147
|
install,
|
|
22100
22148
|
site,
|
|
22101
22149
|
geo,
|
|
22102
|
-
params
|
|
22150
|
+
params,
|
|
22151
|
+
user
|
|
22103
22152
|
}) => {
|
|
22104
22153
|
const { variables, secrets } = projectInstallValues(maps, kinds, install.ord);
|
|
22105
22154
|
return {
|
|
@@ -22108,9 +22157,13 @@ var buildContext3 = ({
|
|
|
22108
22157
|
geo,
|
|
22109
22158
|
params,
|
|
22110
22159
|
install: { id: install.id, label: install.label },
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22160
|
+
...user === void 0 ? {} : { user: { anonId: user.anonId, globalId: null, properties: {} } },
|
|
22161
|
+
startWorkflow: buildStartWorkflow({
|
|
22162
|
+
ord: install.ord,
|
|
22163
|
+
installId: install.id,
|
|
22164
|
+
installLabel: install.label,
|
|
22165
|
+
anonId: user?.anonId ?? null
|
|
22166
|
+
}),
|
|
22114
22167
|
oauth: buildOauth(env, install.ord),
|
|
22115
22168
|
variables,
|
|
22116
22169
|
secrets,
|
|
@@ -22128,6 +22181,11 @@ var buildContext3 = ({
|
|
|
22128
22181
|
broadcast: message.broadcast
|
|
22129
22182
|
});
|
|
22130
22183
|
},
|
|
22184
|
+
context: (userId) => {
|
|
22185
|
+
return asyncContext(env, () => {
|
|
22186
|
+
return userId;
|
|
22187
|
+
});
|
|
22188
|
+
},
|
|
22131
22189
|
skip: () => {
|
|
22132
22190
|
return { kind: "skip" };
|
|
22133
22191
|
}
|
|
@@ -22171,6 +22229,21 @@ var runWebhook = async (invoke, installs) => {
|
|
|
22171
22229
|
}
|
|
22172
22230
|
return Response.json({ outcomes }, { headers: { [ENDPOINT_OUTCOMES_HEADER]: "1" } });
|
|
22173
22231
|
};
|
|
22232
|
+
var endpointHandler = (bundle, context) => {
|
|
22233
|
+
const endpoints = bundle?.endpoints;
|
|
22234
|
+
const candidate = endpoints !== void 0 && Object.hasOwn(endpoints, context.route) ? endpoints[context.route] : void 0;
|
|
22235
|
+
if (typeof candidate === "function") {
|
|
22236
|
+
return candidate;
|
|
22237
|
+
}
|
|
22238
|
+
const visitor = typeof candidate === "object" && candidate !== null ? candidate.__qintoVisitorEndpoint : void 0;
|
|
22239
|
+
if (typeof visitor !== "function") {
|
|
22240
|
+
return Response.json({ error: "not_found" }, { status: 404 });
|
|
22241
|
+
}
|
|
22242
|
+
if (context.user === void 0) {
|
|
22243
|
+
return Response.json({ error: "invalid_context" }, { status: 400 });
|
|
22244
|
+
}
|
|
22245
|
+
return visitor;
|
|
22246
|
+
};
|
|
22174
22247
|
var dispatchEndpoint = async ({ request, env, versions }) => {
|
|
22175
22248
|
const context = parseContext(request.headers.get(ENDPOINT_CONTEXT_HEADER));
|
|
22176
22249
|
if (context === null) {
|
|
@@ -22179,22 +22252,29 @@ var dispatchEndpoint = async ({ request, env, versions }) => {
|
|
|
22179
22252
|
if (!(context.version in versions)) {
|
|
22180
22253
|
return Response.json({ error: "unknown version" }, { status: 404 });
|
|
22181
22254
|
}
|
|
22182
|
-
const
|
|
22183
|
-
|
|
22184
|
-
|
|
22185
|
-
if (typeof candidate !== "function") {
|
|
22186
|
-
return Response.json({ error: "not_found" }, { status: 404 });
|
|
22255
|
+
const handler = endpointHandler(versions[context.version], context);
|
|
22256
|
+
if (handler instanceof Response) {
|
|
22257
|
+
return handler;
|
|
22187
22258
|
}
|
|
22188
|
-
const handler = candidate;
|
|
22189
22259
|
const body = await request.arrayBuffer();
|
|
22190
22260
|
const maps = parseVariableMaps(env);
|
|
22191
|
-
const { variableKinds, appVariableKinds } =
|
|
22261
|
+
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
22192
22262
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22193
22263
|
const invoke = async (install) => {
|
|
22194
22264
|
return installSpan(install, () => {
|
|
22195
22265
|
return handler(
|
|
22196
22266
|
handlerRequest(request, context, body),
|
|
22197
|
-
buildContext3({
|
|
22267
|
+
buildContext3({
|
|
22268
|
+
env,
|
|
22269
|
+
maps,
|
|
22270
|
+
kinds: variableKinds,
|
|
22271
|
+
appScope,
|
|
22272
|
+
install,
|
|
22273
|
+
site,
|
|
22274
|
+
geo: context.geo,
|
|
22275
|
+
params: context.params,
|
|
22276
|
+
user: context.user
|
|
22277
|
+
})
|
|
22198
22278
|
);
|
|
22199
22279
|
});
|
|
22200
22280
|
};
|
|
@@ -22300,6 +22380,42 @@ var withPipelineRetry = (env, bindings) => {
|
|
|
22300
22380
|
return wrapped;
|
|
22301
22381
|
};
|
|
22302
22382
|
|
|
22383
|
+
// src/rpc-definition.ts
|
|
22384
|
+
var isSchema = (candidate) => {
|
|
22385
|
+
return typeof candidate === "object" && candidate !== null && "~standard" in candidate;
|
|
22386
|
+
};
|
|
22387
|
+
var rpcDefinitionOf = (candidate) => {
|
|
22388
|
+
if (typeof candidate !== "object" || candidate === null || !("__qintoRpc" in candidate)) {
|
|
22389
|
+
return void 0;
|
|
22390
|
+
}
|
|
22391
|
+
const marker = candidate.__qintoRpc;
|
|
22392
|
+
if (typeof marker !== "object" || marker === null || !("handler" in marker) || typeof marker.handler !== "function") {
|
|
22393
|
+
return void 0;
|
|
22394
|
+
}
|
|
22395
|
+
const definition = { handler: marker.handler };
|
|
22396
|
+
if ("input" in marker && isSchema(marker.input)) {
|
|
22397
|
+
definition.input = marker.input;
|
|
22398
|
+
}
|
|
22399
|
+
if ("output" in marker && isSchema(marker.output)) {
|
|
22400
|
+
definition.output = marker.output;
|
|
22401
|
+
}
|
|
22402
|
+
return definition;
|
|
22403
|
+
};
|
|
22404
|
+
var checkAgainst = async (schema, value) => {
|
|
22405
|
+
if (schema === void 0) {
|
|
22406
|
+
return { ok: true, value };
|
|
22407
|
+
}
|
|
22408
|
+
const result = await schema["~standard"].validate(value);
|
|
22409
|
+
if (result.issues === void 0) {
|
|
22410
|
+
return { ok: true, value: result.value };
|
|
22411
|
+
}
|
|
22412
|
+
const message = result.issues.map((issue2) => {
|
|
22413
|
+
const path = (issue2.path ?? []).map((segment) => String(typeof segment === "object" ? segment.key : segment)).join(".");
|
|
22414
|
+
return path === "" ? issue2.message : `${path}: ${issue2.message}`;
|
|
22415
|
+
}).join("; ");
|
|
22416
|
+
return { ok: false, message };
|
|
22417
|
+
};
|
|
22418
|
+
|
|
22303
22419
|
// src/traced-fetch.ts
|
|
22304
22420
|
var MAX_BODY_CHARS = 65536;
|
|
22305
22421
|
var TOO_LARGE = `[not recorded: the body is over ${MAX_BODY_CHARS} characters]`;
|
|
@@ -22446,12 +22562,13 @@ var dispatchUi = async ({ request, env, versions }) => {
|
|
|
22446
22562
|
if (handler === void 0) {
|
|
22447
22563
|
return Response.json({ error: "not_found" }, { status: 404 });
|
|
22448
22564
|
}
|
|
22449
|
-
const { variableKinds, appVariableKinds } =
|
|
22565
|
+
const { variableKinds, appVariableKinds, site } = appContextOf(env);
|
|
22450
22566
|
const maps = parseVariableMaps(env);
|
|
22451
22567
|
const { variables, secrets } = projectInstallValues(maps, variableKinds, context.install.ord);
|
|
22452
22568
|
const { appVariables, appSecrets } = projectAppValues(env, appVariableKinds);
|
|
22453
22569
|
const ctx = {
|
|
22454
22570
|
env,
|
|
22571
|
+
site,
|
|
22455
22572
|
install: { id: context.install.id, label: context.install.label },
|
|
22456
22573
|
installs: projectAllInstallValues(maps, variableKinds, context.installs),
|
|
22457
22574
|
// The install is named rather than inherited: one panel serves every install, and reading the
|
|
@@ -22531,7 +22648,7 @@ var projectAction = (action, installId) => {
|
|
|
22531
22648
|
};
|
|
22532
22649
|
var runInstalls = async (envelope, env, invoke) => {
|
|
22533
22650
|
const maps = parseVariableMaps(env);
|
|
22534
|
-
const { variableKinds: kinds, appVariableKinds } =
|
|
22651
|
+
const { variableKinds: kinds, appVariableKinds, site } = appContextOf(env);
|
|
22535
22652
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22536
22653
|
const groups = [];
|
|
22537
22654
|
let failure2;
|
|
@@ -22540,7 +22657,7 @@ var runInstalls = async (envelope, env, invoke) => {
|
|
|
22540
22657
|
const pushes = [];
|
|
22541
22658
|
const captures = [];
|
|
22542
22659
|
const context = contextCollector();
|
|
22543
|
-
const ctx = buildContext({ env, envelope, install, maps, kinds, appScope, emits, pushes, captures, context });
|
|
22660
|
+
const ctx = buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context });
|
|
22544
22661
|
try {
|
|
22545
22662
|
await installSpan(install, () => {
|
|
22546
22663
|
return invoke(ctx, install);
|
|
@@ -22588,11 +22705,12 @@ var runTransform = async (envelope, env, action, handler) => {
|
|
|
22588
22705
|
const captures = [];
|
|
22589
22706
|
const context = contextCollector();
|
|
22590
22707
|
const maps = parseVariableMaps(env);
|
|
22591
|
-
const { variableKinds: kinds, appVariableKinds } =
|
|
22708
|
+
const { variableKinds: kinds, appVariableKinds, site } = appContextOf(env);
|
|
22592
22709
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22593
22710
|
const { apps: _apps, ...withoutApps } = buildContext({
|
|
22594
22711
|
env,
|
|
22595
22712
|
envelope,
|
|
22713
|
+
site,
|
|
22596
22714
|
install,
|
|
22597
22715
|
maps,
|
|
22598
22716
|
kinds,
|
|
@@ -22660,21 +22778,25 @@ var dispatchRpc = async (envelope, bundle, env) => {
|
|
|
22660
22778
|
if (rpc === void 0) {
|
|
22661
22779
|
return jsonError(400, "rpc envelope carries no rpc call");
|
|
22662
22780
|
}
|
|
22663
|
-
const
|
|
22664
|
-
if (
|
|
22781
|
+
const definition = rpcDefinitionOf(bundle?.rpc?.[rpc.fn]);
|
|
22782
|
+
if (definition === void 0) {
|
|
22665
22783
|
return jsonError(200, `missing handler: rpc.${rpc.fn}`);
|
|
22666
22784
|
}
|
|
22785
|
+
const args = await checkAgainst(definition.input, rpc.args);
|
|
22786
|
+
if (!args.ok) {
|
|
22787
|
+
return json2(200, { v: ENVELOPE_VERSION, error: { code: "invalid_arguments", message: failureMessage(args.message) } });
|
|
22788
|
+
}
|
|
22667
22789
|
const install = envelope.installs[0];
|
|
22668
22790
|
const emits = [];
|
|
22669
22791
|
const pushes = [];
|
|
22670
22792
|
const captures = [];
|
|
22671
22793
|
const context = contextCollector();
|
|
22672
22794
|
const maps = parseVariableMaps(env);
|
|
22673
|
-
const { variableKinds: kinds, appVariableKinds } =
|
|
22795
|
+
const { variableKinds: kinds, appVariableKinds, site } = appContextOf(env);
|
|
22674
22796
|
const appScope = projectAppValues(env, appVariableKinds);
|
|
22675
22797
|
const subject = envelope.user?.anonId ?? null;
|
|
22676
22798
|
const ctx = {
|
|
22677
|
-
...buildContext({ env, envelope, install, maps, kinds, appScope, emits, pushes, captures, context }),
|
|
22799
|
+
...buildContext({ env, envelope, site, install, maps, kinds, appScope, emits, pushes, captures, context }),
|
|
22678
22800
|
context: fetchedContext(
|
|
22679
22801
|
env,
|
|
22680
22802
|
(what) => {
|
|
@@ -22686,14 +22808,18 @@ var dispatchRpc = async (envelope, bundle, env) => {
|
|
|
22686
22808
|
let value;
|
|
22687
22809
|
try {
|
|
22688
22810
|
value = await installSpan(install, () => {
|
|
22689
|
-
return handler(
|
|
22811
|
+
return definition.handler(args.value, ctx);
|
|
22690
22812
|
});
|
|
22691
22813
|
} catch (error61) {
|
|
22692
22814
|
const message = failureMessage(error61);
|
|
22693
22815
|
console.warn(`rpc failed for install ${install.id}: ${message}`);
|
|
22694
22816
|
return json2(200, { v: ENVELOPE_VERSION, error: { message } });
|
|
22695
22817
|
}
|
|
22696
|
-
const
|
|
22818
|
+
const checked = await checkAgainst(definition.output, value);
|
|
22819
|
+
if (!checked.ok) {
|
|
22820
|
+
return jsonError(200, failureMessage(`rpc result does not match the output schema: ${checked.message}`));
|
|
22821
|
+
}
|
|
22822
|
+
const result = checked.value === void 0 ? null : checked.value;
|
|
22697
22823
|
if (new TextEncoder().encode(JSON.stringify(result)).length > MAX_RPC_BYTES) {
|
|
22698
22824
|
return jsonError(200, "rpc result exceeds the size cap");
|
|
22699
22825
|
}
|