@zackbart/connecta 0.28.0 → 0.29.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 +961 -5
- package/README.md +62 -39
- package/bin/connecta.mjs +110 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1632 -1509
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +526 -0
- package/dist/auth-elicitation.js +283 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +368 -224
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +631 -0
- package/dist/config.js +503 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +220 -0
- package/dist/connectors/api-connector.js +214 -0
- package/dist/connectors/api.d.ts +8 -71
- package/dist/connectors/api.js +13 -99
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +108 -25
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1780 -351
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +119 -0
- package/dist/downstream-input.js +323 -0
- package/dist/errors.d.ts +97 -20
- package/dist/errors.js +158 -80
- package/dist/execute.js +453 -305
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +24 -9
- package/dist/executors/quickjs-child.js +3 -4
- package/dist/executors/quickjs-runtime.js +147 -59
- package/dist/executors/quickjs.js +29 -35
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +188 -0
- package/dist/guest-types.d.ts +176 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +25 -257
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +230 -73
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +76 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +285 -209
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +117 -0
- package/dist/oauth-partition.js +17 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +55 -18
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/basecamp/index.d.ts +43 -0
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/breeze/index.d.ts +34 -0
- package/dist/providers/breeze/index.js +1446 -0
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/ccb/index.d.ts +103 -0
- package/dist/providers/ccb/index.js +1725 -0
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/overflow/index.d.ts +60 -0
- package/dist/providers/overflow/index.js +1535 -0
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/planning-center/index.d.ts +59 -0
- package/dist/providers/planning-center/index.js +2199 -0
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/tithely/index.d.ts +49 -0
- package/dist/providers/tithely/index.js +1003 -0
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +108 -171
- package/dist/registry.js +513 -925
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +100 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +356 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +136 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +52 -0
- package/dist/sent-secrets.js +474 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +406 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +166 -0
- package/dist/storage/keys.js +428 -0
- package/dist/storage/memory.js +7 -0
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +534 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +320 -54
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +137 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +434 -0
- package/documentation/architecture.md +665 -230
- package/documentation/auth.md +962 -458
- package/documentation/code-mode.md +501 -312
- package/documentation/meta-tools.md +449 -200
- package/documentation/operator-tests.md +93 -0
- package/documentation/provider-migration-0.29.md +60 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +286 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +125 -35
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +133 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- package/templates/node/src/file-activity.ts +0 -182
package/dist/d1.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { ActivityStore } from "./activity.js";
|
|
2
|
+
import type { KVStorage } from "./types.js";
|
|
3
|
+
import { type SqlActivityOptions } from "./storage/sql.js";
|
|
4
|
+
/**
|
|
5
|
+
* The part of a D1 binding connecta uses. Structural, so this package's
|
|
6
|
+
* declarations do not depend on `@cloudflare/workers-types`; a Worker's
|
|
7
|
+
* `D1Database` satisfies it.
|
|
8
|
+
*/
|
|
9
|
+
export interface D1DatabaseBinding {
|
|
10
|
+
prepare(query: string): D1StatementBinding;
|
|
11
|
+
batch(statements: D1StatementBinding[]): Promise<{
|
|
12
|
+
meta: {
|
|
13
|
+
changes?: number;
|
|
14
|
+
};
|
|
15
|
+
}[]>;
|
|
16
|
+
}
|
|
17
|
+
interface D1StatementBinding {
|
|
18
|
+
bind(...values: unknown[]): D1StatementBinding;
|
|
19
|
+
all(): Promise<{
|
|
20
|
+
results: unknown[];
|
|
21
|
+
}>;
|
|
22
|
+
run(): Promise<{
|
|
23
|
+
meta: {
|
|
24
|
+
changes?: number;
|
|
25
|
+
};
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export type D1ActivityOptions = SqlActivityOptions;
|
|
29
|
+
/**
|
|
30
|
+
* `KVStorage` over a D1 database, with the atomic `compareAndSet` every
|
|
31
|
+
* subsystem relies on. The `connecta_kv` table is created on first use; a
|
|
32
|
+
* database that already holds the 0.28 example's table is read as is.
|
|
33
|
+
*/
|
|
34
|
+
export declare function d1Storage(db: D1DatabaseBinding): KVStorage;
|
|
35
|
+
/**
|
|
36
|
+
* Payload-free activity history in the same D1 database, for
|
|
37
|
+
* `activityHistory({ store })`. Keyset paging on `(occurred_at_ms, id)`; each
|
|
38
|
+
* write prunes a bounded batch of rows older than `retentionDays`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function d1ActivityStore(db: D1DatabaseBinding, options?: D1ActivityOptions): ActivityStore;
|
|
41
|
+
/**
|
|
42
|
+
* The part of a Workers KV binding `copyKvToD1` reads. Structural, like
|
|
43
|
+
* `D1DatabaseBinding`; a Worker's `KVNamespace` satisfies it.
|
|
44
|
+
*/
|
|
45
|
+
export interface KVNamespaceBinding {
|
|
46
|
+
list(options?: {
|
|
47
|
+
limit?: number;
|
|
48
|
+
cursor?: string | null;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
keys: readonly {
|
|
51
|
+
name: string;
|
|
52
|
+
expiration?: number;
|
|
53
|
+
}[];
|
|
54
|
+
list_complete: boolean;
|
|
55
|
+
cursor?: string;
|
|
56
|
+
}>;
|
|
57
|
+
get(key: string, type: "text"): Promise<string | null>;
|
|
58
|
+
}
|
|
59
|
+
export interface KvToD1CopyOptions {
|
|
60
|
+
/** The source KV namespace id. Resume tokens are bound to this identity. */
|
|
61
|
+
source: string;
|
|
62
|
+
/** Resume against the same source and database within seven days. */
|
|
63
|
+
cursor?: string;
|
|
64
|
+
/** Explicit families whose conflicting D1 rows the operator judged stale. */
|
|
65
|
+
overwriteFamilies?: readonly string[];
|
|
66
|
+
/** Compare value hashes and absolute expiries without copying entries. */
|
|
67
|
+
verify?: boolean;
|
|
68
|
+
/** Override the cutover guard only after assessing stale KV state. */
|
|
69
|
+
allowStale?: boolean;
|
|
70
|
+
/** Keys read per call. Default 500; use a smaller budget for large rows. */
|
|
71
|
+
maxKeys?: number;
|
|
72
|
+
}
|
|
73
|
+
/** What a copy did with one family's keys. */
|
|
74
|
+
export interface KvToD1Counts {
|
|
75
|
+
/** Written where D1 held no live entry. */
|
|
76
|
+
copied: number;
|
|
77
|
+
/** D1 already held the same value. */
|
|
78
|
+
unchanged: number;
|
|
79
|
+
/** D1 held a different value or expiry and kept it. */
|
|
80
|
+
conflicts: number;
|
|
81
|
+
/** D1 held a different value or expiry, replaced under `overwriteFamilies`. */
|
|
82
|
+
overwritten: number;
|
|
83
|
+
/** Expired or deleted in Workers KV before it could be read. */
|
|
84
|
+
expired: number;
|
|
85
|
+
/** A key/value/row D1 cannot hold, left in Workers KV. */
|
|
86
|
+
invalid: number;
|
|
87
|
+
/** Exact value hash and expiry match during a verification pass. */
|
|
88
|
+
verified: number;
|
|
89
|
+
/** Missing or different value/expiry during a verification pass. */
|
|
90
|
+
mismatches: number;
|
|
91
|
+
}
|
|
92
|
+
export interface KvToD1CopyResult {
|
|
93
|
+
/** True once the whole namespace has been read. */
|
|
94
|
+
done: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Pass back as `options.cursor` to continue; absent when `done`. A random
|
|
97
|
+
* token: the Workers KV cursor it stands for stays in D1, because that
|
|
98
|
+
* cursor can spell the last key listed.
|
|
99
|
+
*/
|
|
100
|
+
cursor?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Counts by key family (`src/storage/keys.ts`), plus `connector-owned` and
|
|
103
|
+
* `unclassified`. Never a key or a value.
|
|
104
|
+
*/
|
|
105
|
+
families: Record<string, KvToD1Counts>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A copy that stopped. The message is fixed wording that names a family at
|
|
109
|
+
* most, never a key or value, and the binding's own error is not attached:
|
|
110
|
+
* KV and D1 errors can quote either. Entries before `cursor` are copied;
|
|
111
|
+
* rerunning from it is safe while the maintenance window still holds.
|
|
112
|
+
*/
|
|
113
|
+
export declare class KvToD1CopyError extends Error {
|
|
114
|
+
/** Resume point; absent means start over, which is also safe. */
|
|
115
|
+
readonly cursor: string | undefined;
|
|
116
|
+
readonly name = "KvToD1CopyError";
|
|
117
|
+
constructor(message: string,
|
|
118
|
+
/** Resume point; absent means start over, which is also safe. */
|
|
119
|
+
cursor: string | undefined);
|
|
120
|
+
}
|
|
121
|
+
/** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
|
|
122
|
+
export declare function markKvToD1Live(db: D1DatabaseBinding, source: string): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Copy live KV entries verbatim while all writers and traffic are stopped.
|
|
125
|
+
* A live D1 row is kept unless its family is explicitly allowed to overwrite.
|
|
126
|
+
* `verify` reads hashes and absolute expiries without changing copied entries.
|
|
127
|
+
* Results contain counts only. Resume tokens are source-bound atomic claims.
|
|
128
|
+
*/
|
|
129
|
+
export declare function copyKvToD1(kv: KVNamespaceBinding, db: D1DatabaseBinding, options: KvToD1CopyOptions): Promise<KvToD1CopyResult>;
|
|
130
|
+
export {};
|
package/dist/d1.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// `@zackbart/connecta/d1`: connecta's storage on Cloudflare Workers.
|
|
2
|
+
//
|
|
3
|
+
// One D1 database holds everything: `d1Storage(db)` is the deployment's
|
|
4
|
+
// `KVStorage`, and `d1ActivityStore(db)` its activity history. Both create
|
|
5
|
+
// their tables on first use, so binding the database is the whole setup.
|
|
6
|
+
// `copyKvToD1` moves a 0.28 deployment's Workers KV state into it once.
|
|
7
|
+
import { errorLabel } from "./operator-record.js";
|
|
8
|
+
import { familyOfKey, KEY_FAMILIES, KV_COPY_CURSOR_TTL_SECONDS, kvCopyKeys, kvCutoverKeys } from "./storage/keys.js";
|
|
9
|
+
import { copyIntoSql, sqlActivityStore, sqlStorage, } from "./storage/sql.js";
|
|
10
|
+
function d1Driver(db) {
|
|
11
|
+
const prepare = (statement) => statement.params.length > 0 ? db.prepare(statement.sql).bind(...statement.params) : db.prepare(statement.sql);
|
|
12
|
+
return {
|
|
13
|
+
async all(statement) {
|
|
14
|
+
return (await prepare(statement).all()).results;
|
|
15
|
+
},
|
|
16
|
+
async run(statement) {
|
|
17
|
+
return (await prepare(statement).run()).meta.changes ?? 0;
|
|
18
|
+
},
|
|
19
|
+
async batch(statements) {
|
|
20
|
+
// D1 runs a batch as one transaction, in order.
|
|
21
|
+
return (await db.batch(statements.map(prepare))).map((result) => result.meta.changes ?? 0);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `KVStorage` over a D1 database, with the atomic `compareAndSet` every
|
|
27
|
+
* subsystem relies on. The `connecta_kv` table is created on first use; a
|
|
28
|
+
* database that already holds the 0.28 example's table is read as is.
|
|
29
|
+
*/
|
|
30
|
+
export function d1Storage(db) {
|
|
31
|
+
return sqlStorage(d1Driver(db), "d1");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Payload-free activity history in the same D1 database, for
|
|
35
|
+
* `activityHistory({ store })`. Keyset paging on `(occurred_at_ms, id)`; each
|
|
36
|
+
* write prunes a bounded batch of rows older than `retentionDays`.
|
|
37
|
+
*/
|
|
38
|
+
export function d1ActivityStore(db, options) {
|
|
39
|
+
return sqlActivityStore(d1Driver(db), "d1", options);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A copy that stopped. The message is fixed wording that names a family at
|
|
43
|
+
* most, never a key or value, and the binding's own error is not attached:
|
|
44
|
+
* KV and D1 errors can quote either. Entries before `cursor` are copied;
|
|
45
|
+
* rerunning from it is safe while the maintenance window still holds.
|
|
46
|
+
*/
|
|
47
|
+
export class KvToD1CopyError extends Error {
|
|
48
|
+
cursor;
|
|
49
|
+
name = "KvToD1CopyError";
|
|
50
|
+
constructor(message,
|
|
51
|
+
/** Resume point; absent means start over, which is also safe. */
|
|
52
|
+
cursor) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.cursor = cursor;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** D1 string and row limit, in UTF-8 bytes.
|
|
58
|
+
* https://developers.cloudflare.com/d1/platform/limits/
|
|
59
|
+
*/
|
|
60
|
+
const D1_MAX_ROW_BYTES = 2_000_000;
|
|
61
|
+
/** Buffered entries, excluding the single value currently being read. */
|
|
62
|
+
const COPY_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
63
|
+
const COPY_GROUP_KEYS = 50;
|
|
64
|
+
const KV_LIST_LIMIT = 1000;
|
|
65
|
+
const encoder = new TextEncoder();
|
|
66
|
+
// SQLite record header, two TEXT serial types, and an eight-byte expiry.
|
|
67
|
+
// Reserve the worst-case header rather than accepting a row at the boundary.
|
|
68
|
+
const ROW_OVERHEAD_BYTES = 32;
|
|
69
|
+
const emptyCounts = () => ({
|
|
70
|
+
copied: 0,
|
|
71
|
+
unchanged: 0,
|
|
72
|
+
conflicts: 0,
|
|
73
|
+
overwritten: 0,
|
|
74
|
+
expired: 0,
|
|
75
|
+
invalid: 0,
|
|
76
|
+
verified: 0,
|
|
77
|
+
mismatches: 0,
|
|
78
|
+
});
|
|
79
|
+
const OUTCOME_COUNT = {
|
|
80
|
+
copied: "copied",
|
|
81
|
+
unchanged: "unchanged",
|
|
82
|
+
conflict: "conflicts",
|
|
83
|
+
overwritten: "overwritten",
|
|
84
|
+
};
|
|
85
|
+
function errorClass(error) {
|
|
86
|
+
const label = errorLabel(error);
|
|
87
|
+
return label ? ` (${label})` : "";
|
|
88
|
+
}
|
|
89
|
+
const valueHash = async (value) => {
|
|
90
|
+
const hash = await crypto.subtle.digest("SHA-256", encoder.encode(value));
|
|
91
|
+
return Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
92
|
+
};
|
|
93
|
+
/** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
|
|
94
|
+
export async function markKvToD1Live(db, source) {
|
|
95
|
+
if (typeof source !== "string" || !source || source.includes("\0")) {
|
|
96
|
+
throw new TypeError("copyKvToD1 source must be a namespace id");
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await d1Storage(db).set(kvCutoverKeys.source(source), "live");
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw new KvToD1CopyError(`Workers KV to D1 copy stopped: recording cutover failed${errorClass(error)}`, undefined);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Copy live KV entries verbatim while all writers and traffic are stopped.
|
|
107
|
+
* A live D1 row is kept unless its family is explicitly allowed to overwrite.
|
|
108
|
+
* `verify` reads hashes and absolute expiries without changing copied entries.
|
|
109
|
+
* Results contain counts only. Resume tokens are source-bound atomic claims.
|
|
110
|
+
*/
|
|
111
|
+
export async function copyKvToD1(kv, db, options) {
|
|
112
|
+
if (!options?.source || typeof options.source !== "string" || options.source.includes("\0")) {
|
|
113
|
+
throw new TypeError("copyKvToD1 source must be a namespace id");
|
|
114
|
+
}
|
|
115
|
+
const maxKeys = options.maxKeys ?? 500;
|
|
116
|
+
if (!Number.isSafeInteger(maxKeys) || maxKeys < 1) {
|
|
117
|
+
throw new TypeError("copyKvToD1 maxKeys must be a positive integer");
|
|
118
|
+
}
|
|
119
|
+
const allowed = new Set([...KEY_FAMILIES.map((family) => family.name), "connector-owned", "unclassified"]);
|
|
120
|
+
if (options.overwriteFamilies?.some((family) => !allowed.has(family))) {
|
|
121
|
+
throw new TypeError("copyKvToD1 overwriteFamilies contains an unknown family");
|
|
122
|
+
}
|
|
123
|
+
const overwrite = new Set(options.overwriteFamilies ?? []);
|
|
124
|
+
const driver = d1Driver(db);
|
|
125
|
+
const storage = sqlStorage(driver, "d1");
|
|
126
|
+
const remember = async (kvCursor) => {
|
|
127
|
+
const token = crypto.randomUUID();
|
|
128
|
+
await storage.set(kvCopyKeys.cursor(token), JSON.stringify({ source: options.source, cursor: kvCursor }), {
|
|
129
|
+
ttlSeconds: KV_COPY_CURSOR_TTL_SECONDS,
|
|
130
|
+
});
|
|
131
|
+
return token;
|
|
132
|
+
};
|
|
133
|
+
let cursor;
|
|
134
|
+
let pageCursor;
|
|
135
|
+
const families = {};
|
|
136
|
+
const count = (key, field) => {
|
|
137
|
+
(families[familyOfKey(key)] ??= emptyCounts())[field] += 1;
|
|
138
|
+
};
|
|
139
|
+
const unknown = new TypeError("copyKvToD1 cursor is unknown, expired, spent, or belongs to another source; restart under maintenance");
|
|
140
|
+
const stale = new TypeError("copyKvToD1 refuses stale KV after cutover");
|
|
141
|
+
// Validate before any D1 access so a failing binding cannot return raw input
|
|
142
|
+
// as an error's resume point.
|
|
143
|
+
if (options.cursor !== undefined &&
|
|
144
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(options.cursor)) {
|
|
145
|
+
throw unknown;
|
|
146
|
+
}
|
|
147
|
+
const failures = new WeakSet();
|
|
148
|
+
const failure = (message) => {
|
|
149
|
+
const error = new KvToD1CopyError(message, undefined);
|
|
150
|
+
failures.add(error);
|
|
151
|
+
return error;
|
|
152
|
+
};
|
|
153
|
+
try {
|
|
154
|
+
if (!options.allowStale && (await storage.get(kvCutoverKeys.source(options.source))) !== null) {
|
|
155
|
+
throw stale;
|
|
156
|
+
}
|
|
157
|
+
if (options.cursor !== undefined) {
|
|
158
|
+
const key = kvCopyKeys.cursor(options.cursor);
|
|
159
|
+
const stored = await storage.get(key);
|
|
160
|
+
let record = null;
|
|
161
|
+
try {
|
|
162
|
+
record = stored === null ? null : JSON.parse(stored);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* refused below */
|
|
166
|
+
}
|
|
167
|
+
if (!record || record.source !== options.source || typeof record.cursor !== "string") {
|
|
168
|
+
throw unknown;
|
|
169
|
+
}
|
|
170
|
+
// Delete only the exact record read: concurrent consumers cannot both win.
|
|
171
|
+
if (!(await storage.compareAndSet(key, stored, null)))
|
|
172
|
+
throw unknown;
|
|
173
|
+
cursor = record.cursor;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (error === unknown || error === stale)
|
|
178
|
+
throw error;
|
|
179
|
+
throw new KvToD1CopyError(`Workers KV to D1 copy stopped: claiming the resume point in D1 failed${errorClass(error)}`, options.cursor);
|
|
180
|
+
}
|
|
181
|
+
const flush = async (buffer) => {
|
|
182
|
+
const entries = buffer.filter((entry) => {
|
|
183
|
+
if (entry.expiresAtMs !== null && entry.expiresAtMs <= Date.now()) {
|
|
184
|
+
count(entry.key, "expired");
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
});
|
|
189
|
+
if (!entries.length)
|
|
190
|
+
return;
|
|
191
|
+
try {
|
|
192
|
+
if (options.verify) {
|
|
193
|
+
for (const entry of entries) {
|
|
194
|
+
const [row] = await driver.all({
|
|
195
|
+
// Read bytes, including NUL, and hash in JS. D1 has no SHA-256 function.
|
|
196
|
+
sql: "SELECT CAST(value AS BLOB) AS value_bytes, expires_at_ms FROM connecta_kv WHERE key = ?",
|
|
197
|
+
params: [entry.key],
|
|
198
|
+
});
|
|
199
|
+
const bytes = row ? Uint8Array.from(row.value_bytes) : undefined;
|
|
200
|
+
const hash = bytes ? await crypto.subtle.digest("SHA-256", bytes) : undefined;
|
|
201
|
+
const hex = hash
|
|
202
|
+
? Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("")
|
|
203
|
+
: undefined;
|
|
204
|
+
count(entry.key, row && row.expires_at_ms === entry.expiresAtMs && hex === (await valueHash(entry.value))
|
|
205
|
+
? "verified"
|
|
206
|
+
: "mismatches");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// Partition only this bounded buffer by overwrite permission.
|
|
211
|
+
for (const replace of [false, true]) {
|
|
212
|
+
const group = entries.filter((entry) => overwrite.has(familyOfKey(entry.key)) === replace);
|
|
213
|
+
if (!group.length)
|
|
214
|
+
continue;
|
|
215
|
+
const outcomes = await copyIntoSql(driver, group, { overwrite: replace, now: Date.now() });
|
|
216
|
+
for (const [index, outcome] of outcomes.entries())
|
|
217
|
+
count(group[index].key, OUTCOME_COUNT[outcome]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
throw failure(`Workers KV to D1 copy stopped: ${options.verify ? "verifying" : "writing to"} D1 failed${errorClass(error)}`);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
let read = 0;
|
|
226
|
+
try {
|
|
227
|
+
for (;;) {
|
|
228
|
+
pageCursor = cursor;
|
|
229
|
+
let page;
|
|
230
|
+
try {
|
|
231
|
+
page = await kv.list({ limit: Math.min(KV_LIST_LIMIT, maxKeys - read), ...(cursor ? { cursor } : {}) });
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
throw failure(`Workers KV to D1 copy stopped: listing Workers KV failed${errorClass(error)}`);
|
|
235
|
+
}
|
|
236
|
+
read += page.keys.length;
|
|
237
|
+
let entries = [];
|
|
238
|
+
let bufferedBytes = 0;
|
|
239
|
+
for (const key of page.keys) {
|
|
240
|
+
const keyBytes = encoder.encode(key.name).byteLength;
|
|
241
|
+
if (key.name.includes("\0") || keyBytes + ROW_OVERHEAD_BYTES > D1_MAX_ROW_BYTES) {
|
|
242
|
+
count(key.name, "invalid");
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const expiresAtMs = key.expiration === undefined ? null : key.expiration * 1000;
|
|
246
|
+
if (expiresAtMs !== null && expiresAtMs <= Date.now()) {
|
|
247
|
+
count(key.name, "expired");
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
let value;
|
|
251
|
+
try {
|
|
252
|
+
value = await kv.get(key.name, "text");
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
throw failure(`Workers KV to D1 copy stopped: reading an entry of the ${familyOfKey(key.name)} family from Workers KV failed${errorClass(error)}`);
|
|
256
|
+
}
|
|
257
|
+
if (value === null || (expiresAtMs !== null && expiresAtMs <= Date.now())) {
|
|
258
|
+
count(key.name, "expired");
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const valueBytes = encoder.encode(value).byteLength;
|
|
262
|
+
const bytes = keyBytes + valueBytes + ROW_OVERHEAD_BYTES;
|
|
263
|
+
if (valueBytes > D1_MAX_ROW_BYTES || bytes > D1_MAX_ROW_BYTES) {
|
|
264
|
+
count(key.name, "invalid");
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (entries.length >= COPY_GROUP_KEYS || bufferedBytes + bytes > COPY_BUFFER_BYTES) {
|
|
268
|
+
await flush(entries);
|
|
269
|
+
entries = [];
|
|
270
|
+
bufferedBytes = 0;
|
|
271
|
+
}
|
|
272
|
+
entries.push({ key: key.name, value, expiresAtMs });
|
|
273
|
+
bufferedBytes += bytes;
|
|
274
|
+
}
|
|
275
|
+
await flush(entries);
|
|
276
|
+
if (page.list_complete || !page.cursor)
|
|
277
|
+
return { done: true, families };
|
|
278
|
+
cursor = page.cursor;
|
|
279
|
+
if (read >= maxKeys)
|
|
280
|
+
return { done: false, cursor: await remember(cursor), families };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
// The old token was claimed atomically. Replace it on failure, if D1 works.
|
|
285
|
+
const resume = pageCursor === undefined ? undefined : await remember(pageCursor).catch(() => undefined);
|
|
286
|
+
throw new KvToD1CopyError(error instanceof KvToD1CopyError && failures.has(error)
|
|
287
|
+
? error.message
|
|
288
|
+
: `Workers KV to D1 copy stopped: recording the resume point in D1 failed${errorClass(error)}`, resume);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { CONFIG_DEFAULTS } from "./config-defaults.js";
|
|
2
|
+
import type { ConnectaConfig, ResolvedConfig } from "./config.js";
|
|
3
|
+
import type { ConnectorAuthDescription, ConnectorDescription, ConnectorToolDescription, DescribedEndpoint } from "./types.js";
|
|
4
|
+
/** Where a limit's value came from. */
|
|
5
|
+
export type ConfigValueSource = "default" | "config";
|
|
6
|
+
/** One limit and where its value came from. `null` means unset (no bound). */
|
|
7
|
+
export interface DescribedLimit<T = number> {
|
|
8
|
+
value: T | null;
|
|
9
|
+
source: ConfigValueSource;
|
|
10
|
+
}
|
|
11
|
+
/** One connector as `describeConfig()` reports it. */
|
|
12
|
+
export interface DescribedConnector {
|
|
13
|
+
id: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
authScope: "shared" | "personal";
|
|
17
|
+
source: ConnectorDescription["source"];
|
|
18
|
+
endpoint?: DescribedEndpoint;
|
|
19
|
+
auth?: ConnectorAuthDescription;
|
|
20
|
+
transport?: ConnectorDescription["transport"];
|
|
21
|
+
/** The operator-managed credential slot: labels and field names, never values. */
|
|
22
|
+
credential?: {
|
|
23
|
+
label: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
fields?: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
label: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
maxResultBytes: {
|
|
32
|
+
value: number;
|
|
33
|
+
source: "connector" | "deployment";
|
|
34
|
+
};
|
|
35
|
+
/** Call admission as numbers; a partition-key function is `partitioned: true`. */
|
|
36
|
+
callAdmission?: {
|
|
37
|
+
maxPartitions?: number;
|
|
38
|
+
rules: Array<{
|
|
39
|
+
maxConcurrency?: number;
|
|
40
|
+
maxQueueSize?: number;
|
|
41
|
+
queueTimeoutMs?: number;
|
|
42
|
+
retryAfterMs?: number;
|
|
43
|
+
budget?: {
|
|
44
|
+
maxCalls: number;
|
|
45
|
+
windowMs: number;
|
|
46
|
+
};
|
|
47
|
+
partitioned: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
usageGuide?: {
|
|
51
|
+
summary?: string;
|
|
52
|
+
required: boolean;
|
|
53
|
+
};
|
|
54
|
+
tools?: ConnectorToolDescription[];
|
|
55
|
+
}
|
|
56
|
+
/** The secret-free deployment snapshot returned by `Connecta.describeConfig()`. */
|
|
57
|
+
export interface ConnectaConfigDescription {
|
|
58
|
+
schemaVersion: 1;
|
|
59
|
+
/** The connecta package version running, never the configurable serverInfo.version. */
|
|
60
|
+
connectaVersion: string;
|
|
61
|
+
server: {
|
|
62
|
+
name: string;
|
|
63
|
+
version: string;
|
|
64
|
+
title?: string;
|
|
65
|
+
websiteUrl?: DescribedEndpoint;
|
|
66
|
+
icons: number;
|
|
67
|
+
};
|
|
68
|
+
urls: {
|
|
69
|
+
publicUrl?: DescribedEndpoint;
|
|
70
|
+
mcpPath: "/mcp";
|
|
71
|
+
/** Configured exact origins, `"*"`, or the default (publicUrl plus loopback). */
|
|
72
|
+
allowedOrigins: string[] | "*" | "default";
|
|
73
|
+
};
|
|
74
|
+
executor: {
|
|
75
|
+
name?: string;
|
|
76
|
+
/** The fallback pool core wraps around the executor, or the executor's own. */
|
|
77
|
+
admission: "executor" | Record<keyof typeof CONFIG_DEFAULTS.admission.code, DescribedLimit>;
|
|
78
|
+
};
|
|
79
|
+
limits: {
|
|
80
|
+
discovery: Record<keyof typeof CONFIG_DEFAULTS.discovery, DescribedLimit<number | boolean>>;
|
|
81
|
+
calls: {
|
|
82
|
+
defaultTimeoutMs: DescribedLimit;
|
|
83
|
+
maxResultBytes: DescribedLimit;
|
|
84
|
+
};
|
|
85
|
+
results: Record<keyof typeof CONFIG_DEFAULTS.results, DescribedLimit>;
|
|
86
|
+
execute: Record<keyof typeof CONFIG_DEFAULTS.execute, DescribedLimit>;
|
|
87
|
+
requests: Record<keyof typeof CONFIG_DEFAULTS.admission.requests, DescribedLimit>;
|
|
88
|
+
};
|
|
89
|
+
/** Trust and exact classification overrides from deployment code. */
|
|
90
|
+
trust: "trusted" | "read-only";
|
|
91
|
+
classification: Record<string, Record<string, "read" | "write">>;
|
|
92
|
+
/** Inbound auth providers in the order they are tried. */
|
|
93
|
+
auth: Array<{
|
|
94
|
+
kind: string;
|
|
95
|
+
interactive: boolean;
|
|
96
|
+
ui?: string;
|
|
97
|
+
}>;
|
|
98
|
+
identity: Record<"connectorAccess" | "activityAccess" | "credentialAdministration" | "accessTokenManagement" | "personalConnection", "default" | "custom">;
|
|
99
|
+
pools: Array<{
|
|
100
|
+
name: string;
|
|
101
|
+
path: string;
|
|
102
|
+
tools: string[];
|
|
103
|
+
hasGrant: boolean;
|
|
104
|
+
trust: "trusted" | "read-only";
|
|
105
|
+
}>;
|
|
106
|
+
modules: {
|
|
107
|
+
ui: {
|
|
108
|
+
enabled: boolean;
|
|
109
|
+
};
|
|
110
|
+
vault: {
|
|
111
|
+
enabled: boolean;
|
|
112
|
+
sealsOAuth?: boolean;
|
|
113
|
+
};
|
|
114
|
+
activity: {
|
|
115
|
+
enabled: boolean;
|
|
116
|
+
readable?: boolean;
|
|
117
|
+
deploymentId?: string;
|
|
118
|
+
store?: {
|
|
119
|
+
kind: DescribedStoreKind;
|
|
120
|
+
retentionDays?: number;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
accessTokens: {
|
|
124
|
+
enabled: boolean;
|
|
125
|
+
maxActive?: number;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
/** Every accepted store implements `list` and `compareAndSet`, so only its kind is told. */
|
|
129
|
+
storage: {
|
|
130
|
+
configured: boolean;
|
|
131
|
+
kind: DescribedStoreKind;
|
|
132
|
+
};
|
|
133
|
+
branding: {
|
|
134
|
+
productName: string;
|
|
135
|
+
productUrl?: string;
|
|
136
|
+
ownerName?: string;
|
|
137
|
+
ownerUrl?: string;
|
|
138
|
+
description: string;
|
|
139
|
+
faviconHref: string;
|
|
140
|
+
themeColor: string;
|
|
141
|
+
theme: {
|
|
142
|
+
accent?: string;
|
|
143
|
+
radius?: string;
|
|
144
|
+
fontFamily?: string;
|
|
145
|
+
monoFamily?: string;
|
|
146
|
+
colorScheme: string;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
/** Names of `deploymentInfo` keys; their values are served by /health only. */
|
|
150
|
+
deploymentInfo: string[];
|
|
151
|
+
connectors: DescribedConnector[];
|
|
152
|
+
}
|
|
153
|
+
export interface DescribeConfigInput {
|
|
154
|
+
registry: import("./registry.js").Registry;
|
|
155
|
+
raw: ConnectaConfig;
|
|
156
|
+
config: ResolvedConfig;
|
|
157
|
+
executorName: string | undefined;
|
|
158
|
+
/** True when the executor owns admission, so `admission.code` is unused. */
|
|
159
|
+
executorAdmits: boolean;
|
|
160
|
+
}
|
|
161
|
+
/** A shipped adapter's own kind; anything else is `"custom"`, so a description carries no free text. */
|
|
162
|
+
type DescribedStoreKind = "memory" | "d1" | "sqlite" | "custom";
|
|
163
|
+
/** Build the snapshot. Pure: it reads configuration and calls only describe hooks. */
|
|
164
|
+
export declare function describeConfig(input: DescribeConfigInput): ConnectaConfigDescription;
|
|
165
|
+
export {};
|