@zackbart/connecta 0.37.0 → 0.38.0
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/CHANGELOG.md +80 -0
- package/README.md +2 -2
- package/bin/connecta.mjs +1 -39
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.js +2 -4
- package/dist/agent-identity.js +1 -1
- package/dist/auth/clerk-sdk/generated.js +2 -1
- package/dist/auth/cloudflare-access.d.ts +3 -1
- package/dist/auth/cloudflare-access.js +22 -11
- package/dist/auth/downstream-oauth.js +195 -270
- package/dist/auth/downstream-revocation.js +1 -1
- package/dist/auth/oauth-grant.js +11 -0
- package/dist/auth/oauth-token-response.js +1 -1
- package/dist/auth/vercel-agent.js +2 -1
- package/dist/auth-elicitation.js +2 -2
- package/dist/branding.d.ts +1 -15
- package/dist/branding.js +2 -2
- package/dist/bytes.js +42 -0
- package/dist/call-admission-context.js +2 -5
- package/dist/call-admission.js +5 -0
- package/dist/call-recovery.js +0 -3
- package/dist/catalog-cache.js +26 -7
- package/dist/catalog-fingerprint.js +2 -18
- package/dist/catalog-revision.js +9 -0
- package/dist/catalog-service.js +51 -20
- package/dist/config-defaults.d.ts +1 -0
- package/dist/config-defaults.js +1 -0
- package/dist/config-schema.d.ts +1 -1
- package/dist/config-schema.js +6 -2
- package/dist/config.d.ts +41 -14
- package/dist/config.js +21 -71
- package/dist/connector-caller.js +1 -1
- package/dist/connectors/api-connector.js +4 -3
- package/dist/connectors/guarded-fetch.d.ts +0 -6
- package/dist/connectors/guarded-fetch.js +1 -11
- package/dist/connectors/remote-mcp.js +93 -69
- package/dist/connectors/resource-uri.js +0 -4
- package/dist/credentials.js +3 -0
- package/dist/d1.d.ts +0 -89
- package/dist/d1.js +0 -34
- package/dist/downstream-input.js +2 -2
- package/dist/execute.js +161 -116
- package/dist/executor-result.js +2 -1
- package/dist/executors/quickjs-runtime.js +2 -25
- package/dist/executors/quickjs.js +1 -1
- package/dist/guest-runtime.js +5 -3
- package/dist/guest-types.d.ts +5 -5
- package/dist/http/client.js +1 -1
- package/dist/http/errors.js +2 -2
- package/dist/http/json-schema.js +1 -1
- package/dist/http/node-transport.js +0 -1
- package/dist/http/oauth.js +1 -1
- package/dist/http/paging.js +6 -9
- package/dist/http/provider.js +1 -1
- package/dist/http/safety.js +1 -1
- package/dist/http/services.js +1 -8
- package/dist/http/tools.js +1 -7
- package/dist/http/vendor.js +7 -7
- package/dist/identity.js +2 -6
- package/dist/index.js +1 -2
- package/dist/invocation-auth.js +2 -1
- package/dist/invocation.js +8 -2
- package/dist/meta-tools.js +27 -27
- package/dist/native-tools.js +2 -1
- package/dist/oauth-handoff.js +2 -2
- package/dist/operation-vocabulary.js +1 -1
- package/dist/operator-record.d.ts +8 -2
- package/dist/operator-record.js +18 -50
- package/dist/operator-ui/contract.d.ts +4 -2
- package/dist/operator-ui/generated.js +3 -3
- package/dist/operator-ui/model.d.ts +7 -2
- package/dist/program-writes.js +3 -8
- package/dist/provider-call.js +0 -7
- package/dist/provider.d.ts +1 -1
- package/dist/providers/_shared/google/kit.js +1 -6
- package/dist/providers/_shared/google/service-account.js +1 -3
- package/dist/providers/_shared/google/workspace.d.ts +1 -1
- package/dist/providers/_shared/guide.js +3 -0
- package/dist/providers/_shared/json.js +12 -0
- package/dist/providers/_shared/rest/compact-index.js +1 -1
- package/dist/providers/_shared/rest/kit.js +1 -3
- package/dist/providers/_shared/rest/operation-index.js +1 -3
- package/dist/providers/_shared/rest/value-safety.js +26 -28
- package/dist/providers/breeze/api.js +2 -7
- package/dist/providers/breeze/index.js +4 -2
- package/dist/providers/breeze/tools.js +3 -4
- package/dist/providers/ccb/api.js +1 -6
- package/dist/providers/ccb/index.js +2 -1
- package/dist/providers/ccb/tools.js +1 -6
- package/dist/providers/cloudflare/api.js +2 -2
- package/dist/providers/cloudflare/index.js +2 -1
- package/dist/providers/cloudflare/safety.js +3 -3
- package/dist/providers/docs/tools.js +2 -10
- package/dist/providers/drive/tools.js +12 -25
- package/dist/providers/forms/tools.js +1 -9
- package/dist/providers/gmail/tools.js +5 -21
- package/dist/providers/overflow/api.js +1 -3
- package/dist/providers/overflow/index.js +2 -1
- package/dist/providers/overflow/tools.js +3 -7
- package/dist/providers/planning-center/api.js +2 -1
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/planning-center/lib/json-api.js +1 -9
- package/dist/providers/planning-center/tools.js +2 -1
- package/dist/providers/sheets/tools.js +1 -9
- package/dist/providers/slides/tools.js +4 -13
- package/dist/providers/stripe/index.js +2 -1
- package/dist/providers/stripe/safety.js +2 -2
- package/dist/providers/tithely/api.js +2 -7
- package/dist/providers/tithely/index.js +3 -2
- package/dist/providers/tithely/tools.js +7 -5
- package/dist/providers/vercel/api.js +1 -6
- package/dist/providers/vercel/lib/pin.js +1 -1
- package/dist/providers/vercel/safety.js +1 -1
- package/dist/providers/vercel/tools.js +2 -1
- package/dist/redaction-marker.js +2 -2
- package/dist/registry.d.ts +4 -1
- package/dist/registry.js +35 -22
- package/dist/request-principal.js +15 -2
- package/dist/request-state.js +2 -2
- package/dist/routes/access-tokens.js +1 -1
- package/dist/routes/activity-disclosure.js +1 -1
- package/dist/routes/connect.js +2 -2
- package/dist/routes/credentials.js +1 -1
- package/dist/routes/dispatch.js +10 -0
- package/dist/routes/mcp.js +23 -21
- package/dist/routes/oauth-management.js +1 -1
- package/dist/routes/operator.js +53 -7
- package/dist/routes/shared.d.ts +8 -8
- package/dist/routes/shared.js +22 -15
- package/dist/routes/ui-config.js +6 -6
- package/dist/routes/ui-data.js +2 -2
- package/dist/routes/ui.js +9 -4
- package/dist/runtime/call-admission.js +1 -1
- package/dist/runtime/call.js +1 -1
- package/dist/runtime/settlement.js +1 -1
- package/dist/runtime/shared-read.js +2 -15
- package/dist/sent-secrets.d.ts +14 -6
- package/dist/sent-secrets.js +231 -85
- package/dist/server.js +4 -4
- package/dist/skills.js +8 -35
- package/dist/sqlite.d.ts +0 -19
- package/dist/sqlite.js +2 -83
- package/dist/storage/keys.js +29 -124
- package/dist/storage/sql-native.js +14 -111
- package/dist/storage/sql.d.ts +1 -24
- package/dist/storage/sql.js +1 -12
- package/dist/tool-error.js +4 -0
- package/dist/types.d.ts +4 -3
- package/dist/ui.js +3 -0
- package/dist/url-safety.js +0 -4
- package/dist/usage-guide.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +1 -1
- package/documentation/README.md +6 -42
- package/documentation/architecture.md +190 -507
- package/documentation/auth.md +172 -58
- package/documentation/code-mode.md +98 -66
- package/documentation/deploying.md +19 -40
- package/documentation/integrating.md +8 -19
- package/documentation/meta-tools.md +23 -6
- package/documentation/migration-0.33.md +5 -5
- package/documentation/migration-0.34.md +2 -4
- package/documentation/migration-retired-layouts.md +74 -0
- package/documentation/operator-tests.md +19 -119
- package/documentation/operator-ui.md +46 -8
- package/documentation/provider-auth-migration.md +4 -10
- package/documentation/provider-migration-0.29.md +4 -15
- package/examples/worker/AGENTS.md +4 -6
- package/examples/worker/README.md +20 -115
- package/guides/connecting-agents.md +7 -30
- package/guides/how-it-works.md +2 -2
- package/guides/safety-and-trust.md +4 -1
- package/package.json +19 -19
- package/templates/node/README.md +9 -26
- package/templates/node/package.json +1 -1
- package/dist/auth/oauth-v2-migration.js +0 -135
- package/dist/provider-call-facts.d.ts +0 -115
- package/dist/provider-call.d.ts +0 -112
- package/dist/storage/d1-copy.js +0 -255
- package/dist/storage/sql-schema.d.ts +0 -6
- package/examples/worker/kv-to-d1.wrangler.jsonc +0 -26
- package/examples/worker/scripts/copy-kv-to-d1.mjs +0 -162
|
@@ -18,9 +18,10 @@ export interface UiTool extends Pick<OperatorTool, "name" | "address" | "descrip
|
|
|
18
18
|
* (`oauth_required`, which also covers an expired or revoked grant — the
|
|
19
19
|
* status seam cannot tell those apart), an operator-managed credential slot
|
|
20
20
|
* (`credential_required`), or a secret that lives in deployment configuration
|
|
21
|
-
* (`auth_required`).
|
|
21
|
+
* (`auth_required`). Principal forwarding instead reports `caller_refused`,
|
|
22
|
+
* which has no secret-repair prompt.
|
|
22
23
|
*/
|
|
23
|
-
export type UiProblem = "connector_unavailable" | "oauth_required" | "credential_required" | "auth_required" | "credential_mismatch" | "catalog_failed";
|
|
24
|
+
export type UiProblem = "connector_unavailable" | "oauth_required" | "credential_required" | "auth_required" | "caller_refused" | "credential_mismatch" | "catalog_failed";
|
|
24
25
|
/** A stored credential that cannot be used, by cause. */
|
|
25
26
|
export type UiCredentialProblem = "credential_mismatch" | "credential_unreadable";
|
|
26
27
|
interface UiCredentialField {
|
|
@@ -57,6 +58,8 @@ interface UiCredential {
|
|
|
57
58
|
notice?: string;
|
|
58
59
|
}
|
|
59
60
|
export interface UiConnector {
|
|
61
|
+
/** Opaque admitted viewer partition, present on HTTP detail responses. */
|
|
62
|
+
viewerKey?: string;
|
|
60
63
|
/** Complete catalog and status from this detail request, when supported. */
|
|
61
64
|
overlay?: OperatorConnectorOverlay;
|
|
62
65
|
id: string;
|
|
@@ -99,6 +102,8 @@ export interface UiConnector {
|
|
|
99
102
|
}
|
|
100
103
|
export type CredentialManagementCapability = "available" | "requires_operator" | "vault_not_configured" | "no_slots";
|
|
101
104
|
export interface UiData {
|
|
105
|
+
/** Opaque admitted viewer partition, present on HTTP summaries. */
|
|
106
|
+
viewerKey?: string;
|
|
102
107
|
accessTokenManagement?: "available" | "requires_operator";
|
|
103
108
|
serverInfo: Pick<ConnectaConfigDescription["server"], "name" | "version">;
|
|
104
109
|
/** Version of the installed @zackbart/connecta package. */
|
package/dist/program-writes.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { toolError } from "./tool-error.js";
|
|
1
2
|
// Budget and outcome accounting for writes dispatched by programs on writable endpoints.
|
|
2
3
|
// Await each dispatched write once; never conceal an unknown outcome.
|
|
3
4
|
import { CONFIG_DEFAULTS } from "./config-defaults.js";
|
|
4
5
|
import { Effect } from "effect";
|
|
5
|
-
import { jsonResult } from "./meta-tools.js";
|
|
6
6
|
import { classifyWriteOutcome } from "./write-outcome.js";
|
|
7
7
|
/** Writes one program may send (`execute.maxWrites`), unless configured. */
|
|
8
8
|
export const DEFAULT_MAX_WRITES = CONFIG_DEFAULTS.execute.maxWrites;
|
|
@@ -125,7 +125,7 @@ export class ProgramWrites {
|
|
|
125
125
|
// the result, as a direct call reports it: its code and handoff, never
|
|
126
126
|
// retryable, with the write's outcome unknown.
|
|
127
127
|
const handoff = this.handoff;
|
|
128
|
-
return
|
|
128
|
+
return toolError({
|
|
129
129
|
code: handoff?.code ?? "write_outcome_unknown",
|
|
130
130
|
message: handoff
|
|
131
131
|
? "A write this program sent failed authorization after it left, so whether it took effect is unknown, and that is the result rather than what the program returned. It will not be sent again. Check its target before doing anything that depends on it, and give nextAction to the operator to recover the connector. Argument echoes may be partial or absent; use the original arguments if reconciliation requires another call."
|
|
@@ -153,7 +153,7 @@ export class ProgramWrites {
|
|
|
153
153
|
function withWrites(result, writes) {
|
|
154
154
|
const structured = result.structuredContent;
|
|
155
155
|
const error = structured?.error;
|
|
156
|
-
const annotated =
|
|
156
|
+
const annotated = toolError({
|
|
157
157
|
...(error !== null && typeof error === "object"
|
|
158
158
|
? error
|
|
159
159
|
: {
|
|
@@ -171,8 +171,3 @@ function withWrites(result, writes) {
|
|
|
171
171
|
}
|
|
172
172
|
return annotated;
|
|
173
173
|
}
|
|
174
|
-
function errorEnvelope(error) {
|
|
175
|
-
const result = jsonResult({ error });
|
|
176
|
-
result.isError = true;
|
|
177
|
-
return result;
|
|
178
|
-
}
|
package/dist/provider-call.js
CHANGED
|
@@ -261,11 +261,4 @@ export function providerFetch(ctx, provider, auxiliary, send) {
|
|
|
261
261
|
export function inLogicalCall(ctx) {
|
|
262
262
|
return recordedService(ctx, LogicalLedger) !== undefined;
|
|
263
263
|
}
|
|
264
|
-
/**
|
|
265
|
-
* Every resource request dispatched under `ctx`'s logical call, from any
|
|
266
|
-
* ledger, nested ones included; undefined outside one.
|
|
267
|
-
*/
|
|
268
|
-
export function logicalCallRequests(ctx) {
|
|
269
|
-
return ctx ? recordedService(ctx, LogicalLedger)?.sent : undefined;
|
|
270
|
-
}
|
|
271
264
|
export { recordProviderResponse, tracksEveryRequest, tracksRequests, delegatesEachCall, providerBoundary, refusedStatus, vendorRefusal, authorizationFailure, unauthorizedAnswer, renewedAfterUnauthorized, refusalRequest, knownProviderFailure, isKnownProviderFailure, forgetProviderFailure, explainedUnauthorizedVerdict, explainsUnauthorized, settledWrite, isSettledWrite, } from "./provider-call-facts.js";
|
package/dist/provider.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ export interface ProviderGuideBlocks<O> {
|
|
|
120
120
|
select(options: Readonly<O>): readonly string[];
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
|
-
* Facts the provider kit
|
|
123
|
+
* Facts the provider kit declares for `providers:generate`:
|
|
124
124
|
* `drift.json`'s `generated.operations` and the guide's Conventions. Plain
|
|
125
125
|
* data, never read at runtime. The kit's `defineApiProvider` sets them.
|
|
126
126
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord, asArray } from "../json.js";
|
|
1
2
|
// Google Workspace on the provider kit (decision 0010; C.7 step 1 under 0011).
|
|
2
3
|
// Shared by every Workspace product; never its own export. `workspace.ts`
|
|
3
4
|
// keeps shared options, connection parsing and subject resolution;
|
|
@@ -17,12 +18,6 @@ import { delegatedToken, forgetDelegatedToken } from "./service-account.js";
|
|
|
17
18
|
import { subjectFor, workspaceConnection } from "./workspace.js";
|
|
18
19
|
import { tagWorkspaceSubject } from "../../../workspace-subject.js";
|
|
19
20
|
import { googleNamedOperation, requireGoogleIndex } from "./hatch.js";
|
|
20
|
-
function asRecord(value) {
|
|
21
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
22
|
-
}
|
|
23
|
-
function asArray(value) {
|
|
24
|
-
return Array.isArray(value) ? value : [];
|
|
25
|
-
}
|
|
26
21
|
function reasonsOf(tokens) {
|
|
27
22
|
const error = asRecord(asRecord(tokens)["error"]);
|
|
28
23
|
const reasons = new Set();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord } from "../json.js";
|
|
1
2
|
/**
|
|
2
3
|
* A Google service account acting as itself or for Workspace users through
|
|
3
4
|
* domain-wide delegation: the key, signed JWT-bearer assertions and short-lived
|
|
@@ -266,9 +267,6 @@ const tokenTransport = guardedFetch({
|
|
|
266
267
|
// The assertion in the body is the authentication; there is no header.
|
|
267
268
|
authenticate: () => ({}),
|
|
268
269
|
});
|
|
269
|
-
function asRecord(value) {
|
|
270
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
271
|
-
}
|
|
272
270
|
/** The token endpoint's OAuth `error` codes this module names back. */
|
|
273
271
|
const TOKEN_ERROR_CODES = new Set([
|
|
274
272
|
"invalid_request",
|
|
@@ -92,10 +92,10 @@ export declare const GOOGLE_WORKSPACE_OPTIONS: import("../../../config-schema.js
|
|
|
92
92
|
};
|
|
93
93
|
instructions: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
94
94
|
title: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
95
|
+
baseUrl: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
95
96
|
purpose: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
96
97
|
maxResultBytes: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
97
98
|
readOnly: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
98
|
-
baseUrl: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
99
99
|
subject: import("../../../config-schema.js").Field<unknown, unknown, true>;
|
|
100
100
|
};
|
|
101
101
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function asRecord(value) {
|
|
5
|
+
return isRecord(value) ? value : {};
|
|
6
|
+
}
|
|
7
|
+
export function asArray(value) {
|
|
8
|
+
return Array.isArray(value) ? value : [];
|
|
9
|
+
}
|
|
10
|
+
export function compact(value) {
|
|
11
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
12
|
+
}
|
|
@@ -23,7 +23,7 @@ function rowText(packed, row) {
|
|
|
23
23
|
return `[[${parameters.join(",")}],${body}]`;
|
|
24
24
|
}
|
|
25
25
|
/** Recreate the exact old JSON string, for semantic identity/cursor binding. */
|
|
26
|
-
|
|
26
|
+
function expandIndexDetails(packed) {
|
|
27
27
|
limit(packed.length);
|
|
28
28
|
let length = packed.definitions.length + 13; // {"d":defs,"o":[]}
|
|
29
29
|
limit(length);
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
+
import { isRecord } from "../json.js";
|
|
1
2
|
// Shared REST call shapes, pinned-schema conversion and indexed vendor declarations.
|
|
2
3
|
import { Effect, Schema } from "effect";
|
|
3
4
|
import { ConnectorCallError } from "../../../errors.js";
|
|
4
5
|
import { Refusal } from "../../../http/errors.js";
|
|
5
6
|
import { Integer, isMinChars, isMaxChars } from "../../../http/json-schema.js";
|
|
6
7
|
import { vendor as declareVendor, get, head, post, put, patch, del, } from "../../../http/vendor.js";
|
|
7
|
-
function isRecord(value) {
|
|
8
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
9
|
-
}
|
|
10
8
|
function invalid(message) {
|
|
11
9
|
throw new ConnectorCallError("invalid_args", message);
|
|
12
10
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "../json.js";
|
|
1
2
|
import { canonicalJson } from "../../../canonical-json.js";
|
|
2
3
|
import { parseIndexDetails } from "./compact-index.js";
|
|
3
4
|
// The pinned operation index a REST connector validates against before it
|
|
@@ -20,9 +21,6 @@ function words(text) {
|
|
|
20
21
|
.split(/[^a-z0-9]+/)
|
|
21
22
|
.filter(Boolean);
|
|
22
23
|
}
|
|
23
|
-
function isRecord(value) {
|
|
24
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
-
}
|
|
26
24
|
function invalid(message, issues, repair) {
|
|
27
25
|
throw new ConnectorCallError("invalid_args", message, {
|
|
28
26
|
...(issues ? { validation: { issues } } : {}),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { isRecord } from "../json.js";
|
|
2
|
+
// Value safety for every REST vendor: no tool response,
|
|
2
3
|
// success or error, returns a credential (API, service, or bypass tokens,
|
|
3
4
|
// signing secrets, bearer URLs, private keys, temporary credentials, auth
|
|
4
5
|
// headers, authorization verifiers) or a stored secret value (environment
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
// Sent-secret redaction runs first, in the provider kit's parse pass, so a
|
|
35
36
|
// rule that decides on a value can find the placeholder where the vendor
|
|
36
37
|
// wrote what the rule matches. Every such decision input fails closed
|
|
37
|
-
|
|
38
|
+
//: an altered type discriminator applies every resource rule; an
|
|
38
39
|
// altered label or type makes a secret record or a header rule; an altered
|
|
39
40
|
// URL scheme or parameter name withholds the whole URL or its value; an
|
|
40
41
|
// altered key withholds its value; a placeholder that may stand for a
|
|
@@ -204,10 +205,7 @@ export function credentialName(name) {
|
|
|
204
205
|
const normalized = normalizedName(name);
|
|
205
206
|
return containsCredential(normalized) || CREDENTIAL_SUFFIX.test(normalized);
|
|
206
207
|
}
|
|
207
|
-
|
|
208
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
209
|
-
}
|
|
210
|
-
/** A rule's test over one decision input; an input redaction altered passes it (#703). */
|
|
208
|
+
/** A rule's test over one decision input; an input redaction altered passes it. */
|
|
211
209
|
function decides(input, test) {
|
|
212
210
|
return typeof input === "string" && (redactionAltered(input) || test(input));
|
|
213
211
|
}
|
|
@@ -215,7 +213,7 @@ function decides(input, test) {
|
|
|
215
213
|
const PLACEHOLDER_KEYS = new WeakSet();
|
|
216
214
|
/**
|
|
217
215
|
* Whether redaction altered one of a record's keys, so no key-based decision
|
|
218
|
-
* about it can be read
|
|
216
|
+
* about it can be read. Parsed JSON keeps its keys; text the kit
|
|
219
217
|
* redacted whole and a result hook parsed after it (NDJSON, log streams) can
|
|
220
218
|
* carry the placeholder in one.
|
|
221
219
|
*/
|
|
@@ -226,7 +224,7 @@ function keysAltered(value) {
|
|
|
226
224
|
const SCHEME_PREFIX = /^(?:[a-z][a-z0-9+.-]*(?::\/{0,2})?)?$/i;
|
|
227
225
|
/**
|
|
228
226
|
* Whether redaction altered the scheme a whole-string URL decision reads
|
|
229
|
-
|
|
227
|
+
*: the text is no longer URL-shaped, everything before its first
|
|
230
228
|
* placeholder could begin a URL, and more than placeholders follows it. A
|
|
231
229
|
* URL a vendor sends holds no whitespace.
|
|
232
230
|
*/
|
|
@@ -434,7 +432,7 @@ function endsValue(text, at) {
|
|
|
434
432
|
/**
|
|
435
433
|
* Where a word at `start` holds a placeholder in place of a link's scheme
|
|
436
434
|
* and host (`[redacted]/pkg?token=…`, `https:[redacted]…`), or `-1`:
|
|
437
|
-
* redaction took the authority that makes text a link
|
|
435
|
+
* redaction took the authority that makes text a link. A Markdown
|
|
438
436
|
* label (`[redacted](…)`) is not one; its destination is read as a link.
|
|
439
437
|
*/
|
|
440
438
|
function markerLed(text, start) {
|
|
@@ -524,7 +522,7 @@ function linkSpan(text, start, host, inline) {
|
|
|
524
522
|
/**
|
|
525
523
|
* Visit each destination once, respecting its CommonMark close and encoded
|
|
526
524
|
* delimiters. Redaction (`failClosed`) also reads a link whose scheme and
|
|
527
|
-
* host redaction took
|
|
525
|
+
* host redaction took; admission never does.
|
|
528
526
|
*/
|
|
529
527
|
function* linkSpans(text, failClosed = false) {
|
|
530
528
|
const markers = failClosed && redactionAltered(text);
|
|
@@ -585,7 +583,7 @@ function credentialQuery(text) {
|
|
|
585
583
|
const fragment = decoded.indexOf("#");
|
|
586
584
|
if (fragment >= 0) {
|
|
587
585
|
const words = decodeLinkText(decoded.slice(fragment + 1));
|
|
588
|
-
// A fragment redaction altered cannot be read
|
|
586
|
+
// A fragment redaction altered cannot be read.
|
|
589
587
|
if (/token|secret|key|code|auth/i.test(words) || alteredFragment(words))
|
|
590
588
|
return true;
|
|
591
589
|
}
|
|
@@ -597,7 +595,7 @@ function credentialQuery(text) {
|
|
|
597
595
|
const equals = pair.indexOf("=");
|
|
598
596
|
at = end + 1;
|
|
599
597
|
// A component redaction altered with no readable name (its name, or its `=`, taken) may be a
|
|
600
|
-
// credential parameter's value, however encoded
|
|
598
|
+
// credential parameter's value, however encoded.
|
|
601
599
|
if (pair !== REDACTED && redactionAltered(equals < 0 ? pair : pair.slice(0, equals)))
|
|
602
600
|
return true;
|
|
603
601
|
if (equals < 0)
|
|
@@ -615,7 +613,7 @@ function withholdLinkQueries(text) {
|
|
|
615
613
|
let out = "";
|
|
616
614
|
let copied = 0;
|
|
617
615
|
for (const { cut, open, end, start, host } of linkSpans(text, true)) {
|
|
618
|
-
// A parameter name redaction altered cannot be read, so the whole link goes
|
|
616
|
+
// A parameter name redaction altered cannot be read, so the whole link goes.
|
|
619
617
|
const whole = alteredLink(text.slice(host, end));
|
|
620
618
|
if (!whole && (cut < 0 || !credentialQuery(text.slice(cut, end))))
|
|
621
619
|
continue;
|
|
@@ -640,7 +638,7 @@ function withholdLinkQueries(text) {
|
|
|
640
638
|
}
|
|
641
639
|
return copied === 0 ? text : out + text.slice(copied);
|
|
642
640
|
}
|
|
643
|
-
/** Whether redaction altered a parameter name in a link's own path, query, or fragment
|
|
641
|
+
/** Whether redaction altered a parameter name in a link's own path, query, or fragment. */
|
|
644
642
|
function alteredLink(link) {
|
|
645
643
|
return redactionAltered(link) && parameterNames(decodeLinkText(link)).some(redactionAltered);
|
|
646
644
|
}
|
|
@@ -676,7 +674,7 @@ function withholdSigningParams(anchored) {
|
|
|
676
674
|
}
|
|
677
675
|
const NAME_CHAR = /[\w.%~;-]/;
|
|
678
676
|
const NAME_ESCAPE = new RegExp(Array.from("abcdefghijklmnopqrstuvwxyz0123456789_.~-", signingName).join("|"), "iy");
|
|
679
|
-
/** Where a parameter's value ends, reading placeholders and character references whole
|
|
677
|
+
/** Where a parameter's value ends, reading placeholders and character references whole. */
|
|
680
678
|
function valueEnd(text, at, inferred) {
|
|
681
679
|
while (at < text.length) {
|
|
682
680
|
const reference = Math.max(characterReferenceEnd(text, at, inferred), bareReferenceEnd(text, at, inferred));
|
|
@@ -693,7 +691,7 @@ function valueEnd(text, at, inferred) {
|
|
|
693
691
|
}
|
|
694
692
|
/**
|
|
695
693
|
* The next placeholder that may hide a signing parameter, at or after `from`,
|
|
696
|
-
* and its value boundary when a name is recognized
|
|
694
|
+
* and its value boundary when a name is recognized. Redaction may have taken a signing name, its
|
|
697
695
|
* `=`, and the start of its value, so a placeholder followed by any of a
|
|
698
696
|
* value's base64 or base64url characters (`+`, `/`, `=`, `-`, `_` included)
|
|
699
697
|
* or `%` escapes goes with them, however short. References count when they
|
|
@@ -956,7 +954,7 @@ function labelsOf(value) {
|
|
|
956
954
|
}
|
|
957
955
|
/**
|
|
958
956
|
* Whether a record's label names a credential, so its value or args are one.
|
|
959
|
-
* A label redaction altered, or keys that may hide one, does too
|
|
957
|
+
* A label redaction altered, or keys that may hide one, does too.
|
|
960
958
|
*/
|
|
961
959
|
function credentialLabelled(value) {
|
|
962
960
|
if (!isRecord(value))
|
|
@@ -966,17 +964,17 @@ function credentialLabelled(value) {
|
|
|
966
964
|
(isRecord(target) && keysAltered(target)) ||
|
|
967
965
|
labelsOf(value).some((label) => decides(label, credentialName)));
|
|
968
966
|
}
|
|
969
|
-
/** A record typed as a secret (`secret_text`); a type redaction altered may have been one
|
|
967
|
+
/** A record typed as a secret (`secret_text`); a type redaction altered may have been one. */
|
|
970
968
|
function typedSecret(value) {
|
|
971
969
|
return keysAltered(value) || decides(value["type"], (type) => /secret/i.test(type));
|
|
972
970
|
}
|
|
973
|
-
/** A list item typed as an environment variable; a type redaction altered may have been one
|
|
971
|
+
/** A list item typed as an environment variable; a type redaction altered may have been one. */
|
|
974
972
|
function envTyped(value) {
|
|
975
973
|
if (!isRecord(value))
|
|
976
974
|
return false;
|
|
977
975
|
return keysAltered(value) || decides(String(value["type"]), (type) => /env/i.test(type));
|
|
978
976
|
}
|
|
979
|
-
/** A header, cookie, or query rule (`request.headers`, `header`, `cookie`, `query`, …); likewise
|
|
977
|
+
/** A header, cookie, or query rule (`request.headers`, `header`, `cookie`, `query`, …); likewise. */
|
|
980
978
|
function headerLike(value) {
|
|
981
979
|
return isRecord(value) && (keysAltered(value) || decides(value["type"], (type) => /header|cookie|query/i.test(type)));
|
|
982
980
|
}
|
|
@@ -989,7 +987,7 @@ function headerValues(value) {
|
|
|
989
987
|
if (isRecord(value))
|
|
990
988
|
return Object.fromEntries(Object.keys(value).map((name) => [name, REDACTED]));
|
|
991
989
|
if (Array.isArray(value)) {
|
|
992
|
-
// A pair whose keys redaction altered may hold its value under any of them
|
|
990
|
+
// A pair whose keys redaction altered may hold its value under any of them.
|
|
993
991
|
return value.map((item) => !isRecord(item)
|
|
994
992
|
? item
|
|
995
993
|
: keysAltered(item)
|
|
@@ -1120,7 +1118,7 @@ function scrubEnv(value, depth) {
|
|
|
1120
1118
|
if (depth > 32)
|
|
1121
1119
|
return REDACTED;
|
|
1122
1120
|
if (Array.isArray(value)) {
|
|
1123
|
-
// A `NAME=value` string, or one whose name and `=` redaction may have taken
|
|
1121
|
+
// A `NAME=value` string, or one whose name and `=` redaction may have taken.
|
|
1124
1122
|
return value.map((item) => typeof item === "string" && (item.includes("=") || redactionAltered(item)) ? REDACTED : scrubEnv(item, depth + 1));
|
|
1125
1123
|
}
|
|
1126
1124
|
if (!isRecord(value))
|
|
@@ -1159,7 +1157,7 @@ function scrubValues(value, depth) {
|
|
|
1159
1157
|
}
|
|
1160
1158
|
return out;
|
|
1161
1159
|
}
|
|
1162
|
-
/** Every rule's paths and withheld fields: the rule for an object whose type redaction altered
|
|
1160
|
+
/** Every rule's paths and withheld fields: the rule for an object whose type redaction altered. */
|
|
1163
1161
|
const ANY_RULE = new WeakMap();
|
|
1164
1162
|
function anyRule(resources) {
|
|
1165
1163
|
let rule = ANY_RULE.get(resources);
|
|
@@ -1172,7 +1170,7 @@ function anyRule(resources) {
|
|
|
1172
1170
|
}
|
|
1173
1171
|
/**
|
|
1174
1172
|
* What a record's type discriminator selects. A type redaction altered, or
|
|
1175
|
-
* one an altered key may hide, selects every rule at once
|
|
1173
|
+
* one an altered key may hide, selects every rule at once.
|
|
1176
1174
|
*/
|
|
1177
1175
|
function typed(record, key, rules, any) {
|
|
1178
1176
|
const type = record[key];
|
|
@@ -1247,7 +1245,7 @@ function heuristic(value, exempt) {
|
|
|
1247
1245
|
if (!exempt.reviewedUrls)
|
|
1248
1246
|
return URL_SHAPE.test(current) ? sanitizeUrl(current) : current;
|
|
1249
1247
|
// A placeholder's own brackets are not Markdown; a URL whose scheme redaction
|
|
1250
|
-
// altered may still carry userinfo, so it is withheld whole
|
|
1248
|
+
// altered may still carry userinfo, so it is withheld whole.
|
|
1251
1249
|
const altered = redactionAltered(current);
|
|
1252
1250
|
if (TEXT.test(altered ? current.replaceAll(REDACTED, "") : current))
|
|
1253
1251
|
return current;
|
|
@@ -1269,7 +1267,7 @@ function heuristic(value, exempt) {
|
|
|
1269
1267
|
const normalized = normalizedName(key);
|
|
1270
1268
|
const review = Object.hasOwn(exempt.fields, key) ? exempt.fields[key] : undefined;
|
|
1271
1269
|
if (!placeholders && redactionAltered(key)) {
|
|
1272
|
-
// A key redaction altered may have named a credential
|
|
1270
|
+
// A key redaction altered may have named a credential.
|
|
1273
1271
|
out[key] = withheld(item);
|
|
1274
1272
|
}
|
|
1275
1273
|
else if (review?.verdict === "redact") {
|
|
@@ -1313,7 +1311,7 @@ function heuristic(value, exempt) {
|
|
|
1313
1311
|
typeof item === "string" &&
|
|
1314
1312
|
(URL_SHAPE.test(item) || alteredScheme(item))) {
|
|
1315
1313
|
// An external destination can carry its secret in the path; relative paths stay.
|
|
1316
|
-
// One whose scheme redaction altered does not parse, so it is withheld
|
|
1314
|
+
// One whose scheme redaction altered does not parse, so it is withheld.
|
|
1317
1315
|
out[key] = originOnly(item);
|
|
1318
1316
|
}
|
|
1319
1317
|
else if (typeof item === "string" && verbatim?.has(key)) {
|
|
@@ -1367,7 +1365,7 @@ export function valueSafety(table, index) {
|
|
|
1367
1365
|
}
|
|
1368
1366
|
const resources = table.embeddedUrls.resources;
|
|
1369
1367
|
if (resources) {
|
|
1370
|
-
// A type redaction altered takes every resource's reviewed text paths
|
|
1368
|
+
// A type redaction altered takes every resource's reviewed text paths.
|
|
1371
1369
|
const all = [...new Set(Object.values(resources.paths).flat())];
|
|
1372
1370
|
const any = () => all;
|
|
1373
1371
|
const scan = (value, depth) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord } from "../_shared/json.js";
|
|
1
2
|
// Breeze's reviewed GET-only vendor. HTTP methods do not establish safety: see tools.ts.
|
|
2
3
|
import { Effect, Schema } from "effect";
|
|
3
4
|
import { ConnectorCallError, resendAdvice } from "../../errors.js";
|
|
@@ -9,12 +10,6 @@ import { openapi } from "./openapi.generated.js";
|
|
|
9
10
|
export const DEFAULT_PAGE_SIZE = 100;
|
|
10
11
|
export const MAX_PAGE_SIZE = 1000;
|
|
11
12
|
export const BREEZE_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
12
|
-
export function asRecord(value) {
|
|
13
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
14
|
-
}
|
|
15
|
-
export function asArray(value) {
|
|
16
|
-
return Array.isArray(value) ? value : [];
|
|
17
|
-
}
|
|
18
13
|
// --- The read hatch's allowlist ----------------------------------------------
|
|
19
14
|
/** Reviewed observational endpoints and their documented query names. GET alone establishes nothing. */
|
|
20
15
|
export const READ_ENDPOINTS = new Map([
|
|
@@ -551,7 +546,7 @@ function shortText(value, secrets) {
|
|
|
551
546
|
return value.trim() || undefined;
|
|
552
547
|
if (value === undefined || value === null)
|
|
553
548
|
return undefined;
|
|
554
|
-
// The kit redacted the answer's values and kept its keys
|
|
549
|
+
// The kit redacted the answer's values and kept its keys; serialized, a key is text
|
|
555
550
|
// the cut below could split, so the whole text is checked before it is cut.
|
|
556
551
|
const text = secrets.redact(JSON.stringify(value));
|
|
557
552
|
return text.length > 300 ? `${text.slice(0, 300)}…` : text;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { readOnlyNotice } from "../_shared/guide.js";
|
|
2
|
+
import { asRecord } from "../_shared/json.js";
|
|
1
3
|
import { skill } from "./skill.generated.js";
|
|
2
4
|
import { keys, optionsOf } from "../../config-schema.js";
|
|
3
5
|
import { PROVIDER_COMMON } from "../../connectors/option-shapes.js";
|
|
4
6
|
import { defineApiProvider } from "../../http/provider.js";
|
|
5
|
-
import { accountSummary, admit,
|
|
7
|
+
import { accountSummary, admit, authenticate, BreezeApi, breezeSafety, BREEZE_MAX_RESPONSE_BYTES, BREEZE_INDEX, BREEZE_VERDICTS, BREEZE_NAMED, breezePeoplePage, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, errors, result, } from "./api.js";
|
|
6
8
|
import { breezeTools } from "./tools.js";
|
|
7
9
|
export const BREEZE_HOST_SUFFIX = ".breezechms.com";
|
|
8
10
|
const SUBDOMAIN_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -68,7 +70,7 @@ export const breeze = defineApiProvider({
|
|
|
68
70
|
`Church database: ${normalizeSubdomain(options.subdomain)}${BREEZE_HOST_SUFFIX}.`,
|
|
69
71
|
`Church purpose: ${options.purpose}`,
|
|
70
72
|
"Calendar feed addresses and embed keys are always removed; profile details follow the requested vendor detail level.",
|
|
71
|
-
...(options.readOnly
|
|
73
|
+
...readOnlyNotice(options.readOnly),
|
|
72
74
|
...(options.defaultPageSize !== undefined
|
|
73
75
|
? [`Paged lists return ${options.defaultPageSize} items by default on this connection.`]
|
|
74
76
|
: []),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { asArray, asRecord } from "../_shared/json.js";
|
|
2
|
+
import { compact } from "../_shared/json.js";
|
|
1
3
|
// Breeze's curated surface: projections and profile encoders earn named tools; the standard hatch supplies coverage.
|
|
2
4
|
import { Effect, Schema } from "effect";
|
|
3
5
|
import { ConnectorCallError } from "../../errors.js";
|
|
@@ -6,12 +8,9 @@ import { Integer, isMinChars, isMaxChars } from "../../http/json-schema.js";
|
|
|
6
8
|
import { RequestSecrets, Classification } from "../../http/services.js";
|
|
7
9
|
import { fieldsInput, fieldsProblem, selectFields } from "../../http/fields.js";
|
|
8
10
|
import { read, list, write as writeTool } from "../../http/tools.js";
|
|
9
|
-
import {
|
|
11
|
+
import { READ_ENDPOINTS } from "./api.js";
|
|
10
12
|
const DEFAULT_EVENT_LIMIT = 100;
|
|
11
13
|
const ObjectValue = Schema.Record(Schema.String, Schema.Unknown);
|
|
12
|
-
function compact(value) {
|
|
13
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
14
|
-
}
|
|
15
14
|
function timestamp(value) {
|
|
16
15
|
if (value === undefined)
|
|
17
16
|
return undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord, asArray } from "../_shared/json.js";
|
|
1
2
|
import { CCB_MEDIA_TYPE, CCB_ENVIRONMENTS, CCB_READ_SCOPES, CCB_WRITE_SCOPES, CCB_SENSITIVE_FIELDS, } from "./lib/constants.js";
|
|
2
3
|
// Pushpay ChMS v2 JSON contracts, OAuth, status meanings, admission and privacy.
|
|
3
4
|
// The legacy per-church XML API is outside this provider's scope.
|
|
@@ -56,12 +57,6 @@ export const CCB_ADMISSION = {
|
|
|
56
57
|
},
|
|
57
58
|
],
|
|
58
59
|
};
|
|
59
|
-
function asRecord(value) {
|
|
60
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
61
|
-
}
|
|
62
|
-
function asArray(value) {
|
|
63
|
-
return Array.isArray(value) ? value : [];
|
|
64
|
-
}
|
|
65
60
|
// ---------------------------------------------------------------------------
|
|
66
61
|
// Admission partitions
|
|
67
62
|
// ---------------------------------------------------------------------------
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readOnlyNotice } from "../_shared/guide.js";
|
|
1
2
|
import { CCB_ENVIRONMENTS, CCB_MEDIA_TYPE } from "./lib/constants.js";
|
|
2
3
|
import { skill } from "./skill.generated.js";
|
|
3
4
|
import { keys, optionsOf } from "../../config-schema.js";
|
|
@@ -70,7 +71,7 @@ export const ccb = defineApiProvider({
|
|
|
70
71
|
...(!writable(options)
|
|
71
72
|
? ["Configured scopes permit only reads: ccb_api_write is omitted and writes are refused."]
|
|
72
73
|
: []),
|
|
73
|
-
...(options.readOnly
|
|
74
|
+
...readOnlyNotice(options.readOnly),
|
|
74
75
|
...(options.defaultPerPage !== undefined
|
|
75
76
|
? [`Named lists default to ${options.defaultPerPage} rows on this connection.`]
|
|
76
77
|
: []),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord, asArray } from "../_shared/json.js";
|
|
1
2
|
// CCB v2 curated projections, bound numbered pages and reviewed POST data search.
|
|
2
3
|
import { Effect, Schema } from "effect";
|
|
3
4
|
import { ConnectorCallError } from "../../errors.js";
|
|
@@ -7,12 +8,6 @@ import { Refusal } from "../../http/errors.js";
|
|
|
7
8
|
import { Integer, isMinChars, isMaxChars } from "../../http/json-schema.js";
|
|
8
9
|
import { read, list } from "../../http/tools.js";
|
|
9
10
|
import { callCcb, DEFAULT_PER_PAGE, SEARCH_DOMAINS, CCB_INDEX, ccbPageInfo, } from "./api.js";
|
|
10
|
-
function asRecord(value) {
|
|
11
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12
|
-
}
|
|
13
|
-
function asArray(value) {
|
|
14
|
-
return Array.isArray(value) ? value : [];
|
|
15
|
-
}
|
|
16
11
|
function compact(value) {
|
|
17
12
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined && entry !== null));
|
|
18
13
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeBase64 } from "../../bytes.js";
|
|
1
2
|
// Cloudflare's pinned REST contracts, confinement, framing and failure semantics.
|
|
2
3
|
import { responseMedia } from "../_shared/rest/response-media.js";
|
|
3
4
|
import { EXCLUSIVE_PATH_IDS } from "./lib/path-bounds.js";
|
|
@@ -396,8 +397,7 @@ export class RawUpload {
|
|
|
396
397
|
}
|
|
397
398
|
export function bytesFromBase64(value, field) {
|
|
398
399
|
try {
|
|
399
|
-
|
|
400
|
-
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
400
|
+
return decodeBase64(value);
|
|
401
401
|
}
|
|
402
402
|
catch {
|
|
403
403
|
return invalid(`${field} must be valid base64.`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readOnlyNotice } from "../_shared/guide.js";
|
|
1
2
|
import { skill } from "./skill.generated.js";
|
|
2
3
|
import { keys, optionsOf, variants } from "../../config-schema.js";
|
|
3
4
|
import { CALL_ADMISSION } from "../../provider.js";
|
|
@@ -90,7 +91,7 @@ function usageGuide(options) {
|
|
|
90
91
|
: ["No additional deployment pin: the credential's vendor permissions define its reachable estate."]),
|
|
91
92
|
...(accountId ? [`Default account id: ${accountId}.`] : []),
|
|
92
93
|
...(zoneId ? [`Default zone id: ${zoneId}.`] : []),
|
|
93
|
-
...(options.readOnly
|
|
94
|
+
...readOnlyNotice(options.readOnly),
|
|
94
95
|
],
|
|
95
96
|
required: true,
|
|
96
97
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Cloudflare's reviewed value-safety table
|
|
1
|
+
// Cloudflare's reviewed value-safety table, on the shared mechanism in
|
|
2
2
|
// `../_shared/rest/value-safety.ts`: every operation the detector flags in
|
|
3
3
|
// the pinned spec (`value-safety.candidates.json`) has one verdict here, and
|
|
4
4
|
// `value-safety.node.test.ts` runs the shared harness over it.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// Paths are dot paths into the data a tool returns (Cloudflare's `result`,
|
|
17
17
|
// or the whole body when it is not an envelope); lists are traversed
|
|
18
18
|
// implicitly and `*` matches every key of an object.
|
|
19
|
-
// Embedded URL verdict
|
|
19
|
+
// Embedded URL verdict: reviewed paths + global signing parameters.
|
|
20
20
|
// Evidence: digest-verified schema revision 843eae2fbf4fe774ef9c91021dd34017ac9c970a:
|
|
21
21
|
// builds_BuildLogsResponse.lines (timestamp/log-message tuples),
|
|
22
22
|
// pages_deployment_log.data.line and workers-observability_query_results
|
|
@@ -869,7 +869,7 @@ const OPERATIONS = {
|
|
|
869
869
|
key,
|
|
870
870
|
safe(DESCRIBED_ONLY, "geo_restrictions", "policy_restrictions", "certificates.geo_restrictions"),
|
|
871
871
|
])),
|
|
872
|
-
// Round 3
|
|
872
|
+
// Round 3: candidates the consolidated detector surfaced (the union
|
|
873
873
|
// of the two former detectors, with transfer, claim, invite, key, signing,
|
|
874
874
|
// and webhook families).
|
|
875
875
|
[`GET ${A}/abuse-reports/submitted/{report_id}`]: safe("An abuse report; the authorization statement is the reporter's text."),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asRecord, asArray, compact } from "../_shared/json.js";
|
|
1
2
|
// Google Docs named projections and bounded writes over the provider kit.
|
|
2
3
|
import { Effect, Option } from "effect";
|
|
3
4
|
import { canonicalJson } from "../../canonical-json.js";
|
|
@@ -28,15 +29,6 @@ const DEFAULT_MAX_CHARS = 20_000;
|
|
|
28
29
|
const ELEMENT_PAGE_BYTES = 64 * 1024;
|
|
29
30
|
/** Characters of each index row's text preview. */
|
|
30
31
|
const PREVIEW_CHARS = 80;
|
|
31
|
-
function asRecord(value) {
|
|
32
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
33
|
-
}
|
|
34
|
-
function asArray(value) {
|
|
35
|
-
return Array.isArray(value) ? value : [];
|
|
36
|
-
}
|
|
37
|
-
function compact(value) {
|
|
38
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
39
|
-
}
|
|
40
32
|
function text(value) {
|
|
41
33
|
return typeof value === "string" && value !== "" ? value : undefined;
|
|
42
34
|
}
|
|
@@ -368,7 +360,7 @@ function batchPath(documentId) {
|
|
|
368
360
|
function revisionAfter(reply, dropped) {
|
|
369
361
|
return keptId(asRecord(reply["writeControl"])["requiredRevisionId"], "revisionId", "revisionId", dropped);
|
|
370
362
|
}
|
|
371
|
-
// No cause: what it would carry is a transport, stream, or parser error that can quote the reply
|
|
363
|
+
// No cause: what it would carry is a transport, stream, or parser error that can quote the reply.
|
|
372
364
|
function uncertain(message, ctx) {
|
|
373
365
|
return providerCallFailure(ctx, { title: "Google Docs" }, new ConnectorCallError("connector_call_failed", message, { retryable: false }), {
|
|
374
366
|
dispatched: true,
|