@zackbart/connecta 0.23.0 → 0.24.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.
Files changed (78) hide show
  1. package/AGENTS.md +5 -0
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +18 -10
  4. package/dist/activity-friction.d.ts +3 -0
  5. package/dist/activity-friction.js +19 -0
  6. package/dist/activity.d.ts +11 -2
  7. package/dist/activity.js +15 -19
  8. package/dist/auth/downstream-oauth.d.ts +2 -1
  9. package/dist/auth/downstream-oauth.js +10 -1
  10. package/dist/branding.d.ts +67 -0
  11. package/dist/branding.js +176 -0
  12. package/dist/connectors/remote-mcp.js +3 -5
  13. package/dist/credential-contract.d.ts +24 -0
  14. package/dist/credential-contract.js +1 -0
  15. package/dist/credential-rules.d.ts +85 -0
  16. package/dist/credential-rules.js +107 -0
  17. package/dist/credentials.d.ts +4 -100
  18. package/dist/credentials.js +3 -107
  19. package/dist/index.d.ts +22 -55
  20. package/dist/index.js +30 -58
  21. package/dist/invocation.js +2 -3
  22. package/dist/meta-tools.d.ts +4 -0
  23. package/dist/meta-tools.js +8 -4
  24. package/dist/module-contracts.d.ts +19 -0
  25. package/dist/module-contracts.js +1 -0
  26. package/dist/operator-ui/generated.js +2 -2
  27. package/dist/operator-ui/model.d.ts +6 -3
  28. package/dist/operator-ui/view.d.ts +2 -18
  29. package/dist/operator-ui/view.js +3 -20
  30. package/dist/registry.d.ts +4 -1
  31. package/dist/registry.js +4 -6
  32. package/dist/routes/activity.js +1 -1
  33. package/dist/routes/credentials.js +5 -2
  34. package/dist/routes/mcp.js +7 -3
  35. package/dist/routes/oauth-management.d.ts +2 -0
  36. package/dist/routes/oauth-management.js +108 -0
  37. package/dist/routes/oauth.d.ts +0 -1
  38. package/dist/routes/oauth.js +21 -121
  39. package/dist/routes/shared.d.ts +19 -17
  40. package/dist/routes/shared.js +48 -44
  41. package/dist/routes/ui.js +36 -33
  42. package/dist/server.js +6 -26
  43. package/dist/types.d.ts +2 -0
  44. package/dist/ui.d.ts +15 -70
  45. package/dist/ui.js +176 -317
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/documentation/architecture.md +26 -17
  49. package/documentation/auth.md +61 -106
  50. package/documentation/cloudflare.md +1 -1
  51. package/documentation/connectors.md +1 -1
  52. package/documentation/linear.md +1 -1
  53. package/documentation/meta-tools.md +6 -4
  54. package/documentation/mixpanel.md +1 -1
  55. package/documentation/notion.md +2 -2
  56. package/documentation/operations.md +12 -14
  57. package/documentation/operator-ui.md +82 -104
  58. package/documentation/optional-modules-upgrade.md +243 -0
  59. package/documentation/provider-conventions.md +5 -3
  60. package/documentation/revenuecat.md +1 -1
  61. package/documentation/storage-and-credentials.md +59 -40
  62. package/documentation/stripe.md +1 -1
  63. package/documentation/upgrading.md +29 -4
  64. package/ethos.md +22 -30
  65. package/examples/worker/AGENTS.md +3 -1
  66. package/examples/worker/README.md +68 -84
  67. package/examples/worker/src/d1-activity.ts +1 -1
  68. package/examples/worker/src/index.ts +11 -6
  69. package/package.json +18 -2
  70. package/templates/node/AGENTS.md +8 -6
  71. package/templates/node/README.md +56 -67
  72. package/templates/node/package.json +1 -1
  73. package/templates/node/src/file-activity.ts +1 -1
  74. package/templates/node/src/index.ts +11 -12
  75. package/dist/access-tokens.d.ts +0 -31
  76. package/dist/access-tokens.js +0 -236
  77. package/dist/routes/access-tokens.d.ts +0 -6
  78. package/dist/routes/access-tokens.js +0 -83
@@ -0,0 +1,85 @@
1
+ import type { Connector, ConnectorCredentialConfig } from "./types.js";
2
+ /** Which hook a testable credential is checked with. */
3
+ type CredentialTestMode = "single" | "multiple";
4
+ /** Operator-safe explanation shared by every surface that detects shape drift. */
5
+ export declare const STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR = "Stored credential fields do not match this connector's current declaration. Replace the credential before using or testing this connector.";
6
+ export type StoredCredentialShape = {
7
+ state: "missing";
8
+ } | {
9
+ state: "valid";
10
+ mode: CredentialTestMode;
11
+ /**
12
+ * Stored keys the connector no longer declares, sorted. Harmless — the
13
+ * credential works — but worth telling an operator about, since nothing
14
+ * else in `/ui` can show a field the declaration has stopped naming.
15
+ */
16
+ undeclared: string[];
17
+ } | {
18
+ state: "mismatch";
19
+ mode: CredentialTestMode;
20
+ message: typeof STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR;
21
+ };
22
+ /**
23
+ * Compare a connector's current declaration with the keys in its stored
24
+ * credential. Values are deliberately ignored: callers may pass decrypted
25
+ * values or `/credentials`' masked field metadata and get the same answer.
26
+ *
27
+ * The test is CONTAINMENT, not equality: the stored key set is compatible when
28
+ * it holds every field currently declared — the reserved `value` key for a
29
+ * single-value declaration, every declared name for a named one. Anything the
30
+ * declaration asks for and the vault does not have is `mismatch`, which is
31
+ * precisely what a renamed field, a newly added field, or a swap between the
32
+ * two shapes produces. The swap needs no special case: `value` is never one of
33
+ * the declared names, so single→named and named→single each leave the declared
34
+ * side unsatisfied. An empty stored map (reachable through a hand-written
35
+ * plaintext) satisfies nothing and is a mismatch too.
36
+ *
37
+ * Extra keys are NOT drift. They are what *dropping* a field leaves behind, and
38
+ * every accessor a connector actually uses — `ctx.credential.get("apiKey")`,
39
+ * `getAll().apiKey` — keeps returning the right secret across that redeploy.
40
+ * Calling it drift would order an operator to re-enter a working secret that
41
+ * many providers will not reissue in readable form. The leftovers come back as
42
+ * `undeclared` instead, for a surface to mention without blocking anything.
43
+ */
44
+ export declare function storedCredentialShape(config: ConnectorCredentialConfig, stored: Readonly<Record<string, unknown>> | null): StoredCredentialShape;
45
+ /**
46
+ * The one sentence describing leftover stored fields, so every surface words it
47
+ * the same way. Names only — the values stay in the vault, and a field name from
48
+ * a previous declaration is not a secret. Deliberately reassuring: nothing is
49
+ * broken, and the only thing an operator gains by acting is that a connector
50
+ * iterating `getAll()` stops seeing a field its code no longer knows about.
51
+ */
52
+ export declare function describeUndeclaredCredentialFields(fields: string[]): string;
53
+ /** A declared credential shape whose only test hook cannot test it. */
54
+ export interface CredentialTestMismatch {
55
+ /** The shape the connector declared. */
56
+ shape: CredentialTestMode;
57
+ /** The hook it implements, which that shape cannot use. */
58
+ hook: "testCredential" | "testCredentials";
59
+ }
60
+ export interface CredentialTestRule {
61
+ /** The hook to call, or null when this credential cannot be tested at all. */
62
+ mode: CredentialTestMode | null;
63
+ /** Set only when the sole implemented hook is the one the shape cannot use. */
64
+ mismatch?: CredentialTestMismatch;
65
+ }
66
+ /**
67
+ * The one rule deciding whether a connector's credential can be tested — read
68
+ * by /credentials' `testable` flag, by `POST /ui/credentials/<id>/test` when
69
+ * it picks a hook, and by the construction-time mismatch warning, so those
70
+ * three cannot drift apart.
71
+ *
72
+ * The declared credential *shape* selects the hook: named `credential.fields`
73
+ * are tested as a set by `testCredentials`, a single-value `credential` by
74
+ * `testCredential` on the vault's reserved `value` field. The other hook is
75
+ * never substituted — it would be handed a shape the connector never declared —
76
+ * so a connector implementing only the mismatched hook is not testable, and
77
+ * says so at construction rather than under an operator's click.
78
+ */
79
+ export declare function credentialTestRule(connector: Pick<Connector, "credential" | "testCredential" | "testCredentials">): CredentialTestRule;
80
+ /**
81
+ * One clause naming a mismatch, shared by the startup warning and the test
82
+ * route's 400 so an operator reads the same explanation in both places.
83
+ */
84
+ export declare function describeCredentialTestMismatch(mismatch: CredentialTestMismatch): string;
85
+ export {};
@@ -0,0 +1,107 @@
1
+ /** Operator-safe explanation shared by every surface that detects shape drift. */
2
+ export const STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR = "Stored credential fields do not match this connector's current declaration. Replace the credential before using or testing this connector.";
3
+ /**
4
+ * Compare a connector's current declaration with the keys in its stored
5
+ * credential. Values are deliberately ignored: callers may pass decrypted
6
+ * values or `/credentials`' masked field metadata and get the same answer.
7
+ *
8
+ * The test is CONTAINMENT, not equality: the stored key set is compatible when
9
+ * it holds every field currently declared — the reserved `value` key for a
10
+ * single-value declaration, every declared name for a named one. Anything the
11
+ * declaration asks for and the vault does not have is `mismatch`, which is
12
+ * precisely what a renamed field, a newly added field, or a swap between the
13
+ * two shapes produces. The swap needs no special case: `value` is never one of
14
+ * the declared names, so single→named and named→single each leave the declared
15
+ * side unsatisfied. An empty stored map (reachable through a hand-written
16
+ * plaintext) satisfies nothing and is a mismatch too.
17
+ *
18
+ * Extra keys are NOT drift. They are what *dropping* a field leaves behind, and
19
+ * every accessor a connector actually uses — `ctx.credential.get("apiKey")`,
20
+ * `getAll().apiKey` — keeps returning the right secret across that redeploy.
21
+ * Calling it drift would order an operator to re-enter a working secret that
22
+ * many providers will not reissue in readable form. The leftovers come back as
23
+ * `undeclared` instead, for a surface to mention without blocking anything.
24
+ */
25
+ export function storedCredentialShape(config, stored) {
26
+ if (!stored)
27
+ return { state: "missing" };
28
+ const mode = config.fields?.length
29
+ ? "multiple"
30
+ : "single";
31
+ const declared = new Set(mode === "multiple" ? config.fields.map((field) => field.name) : ["value"]);
32
+ const actual = Object.keys(stored);
33
+ const present = new Set(actual);
34
+ for (const field of declared) {
35
+ if (!present.has(field)) {
36
+ return {
37
+ state: "mismatch",
38
+ mode,
39
+ message: STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR,
40
+ };
41
+ }
42
+ }
43
+ return {
44
+ state: "valid",
45
+ mode,
46
+ undeclared: actual.filter((field) => !declared.has(field)).sort(),
47
+ };
48
+ }
49
+ /** How many leftover field names an advisory names before it summarizes. */
50
+ const UNDECLARED_SAMPLE = 5;
51
+ /**
52
+ * The one sentence describing leftover stored fields, so every surface words it
53
+ * the same way. Names only — the values stay in the vault, and a field name from
54
+ * a previous declaration is not a secret. Deliberately reassuring: nothing is
55
+ * broken, and the only thing an operator gains by acting is that a connector
56
+ * iterating `getAll()` stops seeing a field its code no longer knows about.
57
+ */
58
+ export function describeUndeclaredCredentialFields(fields) {
59
+ const shown = fields.slice(0, UNDECLARED_SAMPLE);
60
+ const rest = fields.length - shown.length;
61
+ const named = shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
62
+ return fields.length === 1
63
+ ? `Stored credential also holds a field this connector no longer declares (${named}). It keeps working; replace the credential to drop it.`
64
+ : `Stored credential also holds fields this connector no longer declares (${named}). It keeps working; replace the credential to drop them.`;
65
+ }
66
+ /**
67
+ * The one rule deciding whether a connector's credential can be tested — read
68
+ * by /credentials' `testable` flag, by `POST /ui/credentials/<id>/test` when
69
+ * it picks a hook, and by the construction-time mismatch warning, so those
70
+ * three cannot drift apart.
71
+ *
72
+ * The declared credential *shape* selects the hook: named `credential.fields`
73
+ * are tested as a set by `testCredentials`, a single-value `credential` by
74
+ * `testCredential` on the vault's reserved `value` field. The other hook is
75
+ * never substituted — it would be handed a shape the connector never declared —
76
+ * so a connector implementing only the mismatched hook is not testable, and
77
+ * says so at construction rather than under an operator's click.
78
+ */
79
+ export function credentialTestRule(connector) {
80
+ if (!connector.credential)
81
+ return { mode: null };
82
+ if (connector.credential.fields?.length) {
83
+ if (connector.testCredentials)
84
+ return { mode: "multiple" };
85
+ return connector.testCredential
86
+ ? { mode: null, mismatch: { shape: "multiple", hook: "testCredential" } }
87
+ : { mode: null };
88
+ }
89
+ if (connector.testCredential)
90
+ return { mode: "single" };
91
+ return connector.testCredentials
92
+ ? { mode: null, mismatch: { shape: "single", hook: "testCredentials" } }
93
+ : { mode: null };
94
+ }
95
+ /**
96
+ * One clause naming a mismatch, shared by the startup warning and the test
97
+ * route's 400 so an operator reads the same explanation in both places.
98
+ */
99
+ export function describeCredentialTestMismatch(mismatch) {
100
+ return mismatch.shape === "multiple"
101
+ ? "it declares named credential fields, which only " +
102
+ "`testCredentials(values, ctx)` can test, but implements " +
103
+ "`testCredential`"
104
+ : "it declares a single-value credential, which only " +
105
+ "`testCredential(value, ctx)` can test, but implements " +
106
+ "`testCredentials`";
107
+ }
@@ -1,107 +1,11 @@
1
- import type { Connector, ConnectorCredentialConfig, ConnectorCredentialValues, KVStorage } from "./types.js";
2
- interface CredentialFieldMetadata {
3
- configured: true;
4
- /** Only emitted when the value is long enough that four chars don't leak much. */
5
- lastFour?: string;
6
- updatedAt: string;
7
- }
8
- export interface CredentialMetadata {
9
- configured: true;
10
- /** Backward-compatible metadata for the reserved single credential field. */
11
- lastFour?: string;
12
- updatedAt: string;
13
- /** Per-field masked metadata for named multi-value credentials. */
14
- fields?: Record<string, CredentialFieldMetadata>;
15
- }
16
- /** Which hook a testable credential is checked with. */
17
- type CredentialTestMode = "single" | "multiple";
18
- /** Operator-safe explanation shared by every surface that detects shape drift. */
19
- export declare const STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR = "Stored credential fields do not match this connector's current declaration. Replace the credential before using or testing this connector.";
20
- export type StoredCredentialShape = {
21
- state: "missing";
22
- } | {
23
- state: "valid";
24
- mode: CredentialTestMode;
25
- /**
26
- * Stored keys the connector no longer declares, sorted. Harmless — the
27
- * credential works — but worth telling an operator about, since nothing
28
- * else in `/ui` can show a field the declaration has stopped naming.
29
- */
30
- undeclared: string[];
31
- } | {
32
- state: "mismatch";
33
- mode: CredentialTestMode;
34
- message: typeof STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR;
35
- };
36
- /**
37
- * Compare a connector's current declaration with the keys in its stored
38
- * credential. Values are deliberately ignored: callers may pass decrypted
39
- * values or `/credentials`' masked field metadata and get the same answer.
40
- *
41
- * The test is CONTAINMENT, not equality: the stored key set is compatible when
42
- * it holds every field currently declared — the reserved `value` key for a
43
- * single-value declaration, every declared name for a named one. Anything the
44
- * declaration asks for and the vault does not have is `mismatch`, which is
45
- * precisely what a renamed field, a newly added field, or a swap between the
46
- * two shapes produces. The swap needs no special case: `value` is never one of
47
- * the declared names, so single→named and named→single each leave the declared
48
- * side unsatisfied. An empty stored map (reachable through a hand-written
49
- * plaintext) satisfies nothing and is a mismatch too.
50
- *
51
- * Extra keys are NOT drift. They are what *dropping* a field leaves behind, and
52
- * every accessor a connector actually uses — `ctx.credential.get("apiKey")`,
53
- * `getAll().apiKey` — keeps returning the right secret across that redeploy.
54
- * Calling it drift would order an operator to re-enter a working secret that
55
- * many providers will not reissue in readable form. The leftovers come back as
56
- * `undeclared` instead, for a surface to mention without blocking anything.
57
- */
58
- export declare function storedCredentialShape(config: ConnectorCredentialConfig, stored: Readonly<Record<string, unknown>> | null): StoredCredentialShape;
59
- /**
60
- * The one sentence describing leftover stored fields, so every surface words it
61
- * the same way. Names only — the values stay in the vault, and a field name from
62
- * a previous declaration is not a secret. Deliberately reassuring: nothing is
63
- * broken, and the only thing an operator gains by acting is that a connector
64
- * iterating `getAll()` stops seeing a field its code no longer knows about.
65
- */
66
- export declare function describeUndeclaredCredentialFields(fields: string[]): string;
67
- /** A declared credential shape whose only test hook cannot test it. */
68
- export interface CredentialTestMismatch {
69
- /** The shape the connector declared. */
70
- shape: CredentialTestMode;
71
- /** The hook it implements, which that shape cannot use. */
72
- hook: "testCredential" | "testCredentials";
73
- }
74
- export interface CredentialTestRule {
75
- /** The hook to call, or null when this credential cannot be tested at all. */
76
- mode: CredentialTestMode | null;
77
- /** Set only when the sole implemented hook is the one the shape cannot use. */
78
- mismatch?: CredentialTestMismatch;
79
- }
80
- /**
81
- * The one rule deciding whether a connector's credential can be tested — read
82
- * by /credentials' `testable` flag, by `POST /ui/credentials/<id>/test` when
83
- * it picks a hook, and by the construction-time mismatch warning, so those
84
- * three cannot drift apart.
85
- *
86
- * The declared credential *shape* selects the hook: named `credential.fields`
87
- * are tested as a set by `testCredentials`, a single-value `credential` by
88
- * `testCredential` on the vault's reserved `value` field. The other hook is
89
- * never substituted — it would be handed a shape the connector never declared —
90
- * so a connector implementing only the mismatched hook is not testable, and
91
- * says so at construction rather than under an operator's click.
92
- */
93
- export declare function credentialTestRule(connector: Pick<Connector, "credential" | "testCredential" | "testCredentials">): CredentialTestRule;
94
- /**
95
- * One clause naming a mismatch, shared by the startup warning and the test
96
- * route's 400 so an operator reads the same explanation in both places.
97
- */
98
- export declare function describeCredentialTestMismatch(mismatch: CredentialTestMismatch): string;
1
+ import type { CredentialMetadata, CredentialVault as Vault } from "./credential-contract.js";
2
+ import type { ConnectorCredentialValues, KVStorage } from "./types.js";
99
3
  /**
100
4
  * Encrypted, connector-scoped credential vault over the deployment's existing
101
5
  * KVStorage. Only ciphertext enters KV; the AES-GCM key remains an environment
102
6
  * secret outside the store.
103
7
  */
104
- export declare class CredentialVault {
8
+ export declare class CredentialVault implements Vault {
105
9
  private readonly storage;
106
10
  private readonly key;
107
11
  constructor(storage: KVStorage, encryptionKey: string);
@@ -114,4 +18,4 @@ export declare class CredentialVault {
114
18
  setAll(connectorId: string, values: ConnectorCredentialValues, updatedBy: string, owner?: string): Promise<CredentialMetadata>;
115
19
  delete(connectorId: string, owner?: string): Promise<void>;
116
20
  }
117
- export {};
21
+ export declare function encryptedCredentialVault(storage: KVStorage, encryptionKey: string): Vault;
@@ -3,113 +3,6 @@ const IV_BYTES = 12;
3
3
  const MAX_CREDENTIAL_BYTES = 16_384;
4
4
  const encoder = new TextEncoder();
5
5
  const decoder = new TextDecoder();
6
- /** Operator-safe explanation shared by every surface that detects shape drift. */
7
- export const STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR = "Stored credential fields do not match this connector's current declaration. Replace the credential before using or testing this connector.";
8
- /**
9
- * Compare a connector's current declaration with the keys in its stored
10
- * credential. Values are deliberately ignored: callers may pass decrypted
11
- * values or `/credentials`' masked field metadata and get the same answer.
12
- *
13
- * The test is CONTAINMENT, not equality: the stored key set is compatible when
14
- * it holds every field currently declared — the reserved `value` key for a
15
- * single-value declaration, every declared name for a named one. Anything the
16
- * declaration asks for and the vault does not have is `mismatch`, which is
17
- * precisely what a renamed field, a newly added field, or a swap between the
18
- * two shapes produces. The swap needs no special case: `value` is never one of
19
- * the declared names, so single→named and named→single each leave the declared
20
- * side unsatisfied. An empty stored map (reachable through a hand-written
21
- * plaintext) satisfies nothing and is a mismatch too.
22
- *
23
- * Extra keys are NOT drift. They are what *dropping* a field leaves behind, and
24
- * every accessor a connector actually uses — `ctx.credential.get("apiKey")`,
25
- * `getAll().apiKey` — keeps returning the right secret across that redeploy.
26
- * Calling it drift would order an operator to re-enter a working secret that
27
- * many providers will not reissue in readable form. The leftovers come back as
28
- * `undeclared` instead, for a surface to mention without blocking anything.
29
- */
30
- export function storedCredentialShape(config, stored) {
31
- if (!stored)
32
- return { state: "missing" };
33
- const mode = config.fields?.length
34
- ? "multiple"
35
- : "single";
36
- const declared = new Set(mode === "multiple" ? config.fields.map((field) => field.name) : ["value"]);
37
- const actual = Object.keys(stored);
38
- const present = new Set(actual);
39
- for (const field of declared) {
40
- if (!present.has(field)) {
41
- return {
42
- state: "mismatch",
43
- mode,
44
- message: STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR,
45
- };
46
- }
47
- }
48
- return {
49
- state: "valid",
50
- mode,
51
- undeclared: actual.filter((field) => !declared.has(field)).sort(),
52
- };
53
- }
54
- /** How many leftover field names an advisory names before it summarizes. */
55
- const UNDECLARED_SAMPLE = 5;
56
- /**
57
- * The one sentence describing leftover stored fields, so every surface words it
58
- * the same way. Names only — the values stay in the vault, and a field name from
59
- * a previous declaration is not a secret. Deliberately reassuring: nothing is
60
- * broken, and the only thing an operator gains by acting is that a connector
61
- * iterating `getAll()` stops seeing a field its code no longer knows about.
62
- */
63
- export function describeUndeclaredCredentialFields(fields) {
64
- const shown = fields.slice(0, UNDECLARED_SAMPLE);
65
- const rest = fields.length - shown.length;
66
- const named = shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
67
- return fields.length === 1
68
- ? `Stored credential also holds a field this connector no longer declares (${named}). It keeps working; replace the credential to drop it.`
69
- : `Stored credential also holds fields this connector no longer declares (${named}). It keeps working; replace the credential to drop them.`;
70
- }
71
- /**
72
- * The one rule deciding whether a connector's credential can be tested — read
73
- * by /credentials' `testable` flag, by `POST /ui/credentials/<id>/test` when
74
- * it picks a hook, and by the construction-time mismatch warning, so those
75
- * three cannot drift apart.
76
- *
77
- * The declared credential *shape* selects the hook: named `credential.fields`
78
- * are tested as a set by `testCredentials`, a single-value `credential` by
79
- * `testCredential` on the vault's reserved `value` field. The other hook is
80
- * never substituted — it would be handed a shape the connector never declared —
81
- * so a connector implementing only the mismatched hook is not testable, and
82
- * says so at construction rather than under an operator's click.
83
- */
84
- export function credentialTestRule(connector) {
85
- if (!connector.credential)
86
- return { mode: null };
87
- if (connector.credential.fields?.length) {
88
- if (connector.testCredentials)
89
- return { mode: "multiple" };
90
- return connector.testCredential
91
- ? { mode: null, mismatch: { shape: "multiple", hook: "testCredential" } }
92
- : { mode: null };
93
- }
94
- if (connector.testCredential)
95
- return { mode: "single" };
96
- return connector.testCredentials
97
- ? { mode: null, mismatch: { shape: "single", hook: "testCredentials" } }
98
- : { mode: null };
99
- }
100
- /**
101
- * One clause naming a mismatch, shared by the startup warning and the test
102
- * route's 400 so an operator reads the same explanation in both places.
103
- */
104
- export function describeCredentialTestMismatch(mismatch) {
105
- return mismatch.shape === "multiple"
106
- ? "it declares named credential fields, which only " +
107
- "`testCredentials(values, ctx)` can test, but implements " +
108
- "`testCredential`"
109
- : "it declares a single-value credential, which only " +
110
- "`testCredential(value, ctx)` can test, but implements " +
111
- "`testCredentials`";
112
- }
113
6
  function storageKey(connectorId, owner) {
114
7
  return owner
115
8
  ? `principal:${owner}:conn:${connectorId}:credential:v1`
@@ -290,3 +183,6 @@ export class CredentialVault {
290
183
  await this.storage.delete(storageKey(connectorId, owner));
291
184
  }
292
185
  }
186
+ export function encryptedCredentialVault(storage, encryptionKey) {
187
+ return new CredentialVault(storage, encryptionKey);
188
+ }
package/dist/index.d.ts CHANGED
@@ -1,34 +1,9 @@
1
+ import type { CredentialVault } from "./credential-contract.js";
1
2
  import { Registry } from "./registry.js";
2
- import type { ActivityReadGate, ActivityStore } from "./activity.js";
3
- import type { AuthenticatedIdentity, Connector, ConnectaBranding, Executor, IdentityReference, InboundAuth, KVStorage, Logger } from "./types.js";
4
- /** Payload-free activity storage and operator-read policy. */
5
- export interface ConnectaActivityConfig {
6
- /**
7
- * Privacy-minimal downstream tool activity storage. Writes are best-effort
8
- * and never change tool results. Implement `list` to enable the Activity UI.
9
- */
10
- store: ActivityStore;
11
- /**
12
- * Optional authorization gate for the Activity read API. MCP authentication
13
- * is still required first. Omit to admit every authenticated actor.
14
- */
15
- readGate?: ActivityReadGate;
16
- /** Stable deployment label included in activity events, e.g. "production". */
17
- deploymentId?: string;
18
- }
19
- /** Operator-vault encryption. */
20
- export interface ConnectaCredentialsConfig {
21
- /**
22
- * Base64-encoded 32-byte AES key for credentials managed on /credentials.
23
- * Keep this in the runtime's secret store, never in KV or source control.
24
- */
25
- encryptionKey?: string;
26
- }
27
- /** Operator-issued credentials for clients connecting to this deployment. */
28
- export interface ConnectaAccessTokensConfig {
29
- /** Maximum simultaneously active access tokens. Defaults to 100. */
30
- maxActive?: number;
31
- }
3
+ import type { ActivityModule, OperatorSurface } from "./module-contracts.js";
4
+ export type { ActivityModule, OperatorSurface } from "./module-contracts.js";
5
+ export type { CredentialVault, CredentialMetadata } from "./credential-contract.js";
6
+ import type { AuthenticatedIdentity, Connector, Executor, IdentityReference, InboundAuth, KVStorage, Logger } from "./types.js";
32
7
  /** Tool-catalog caching, persistence, stale fallback, and probe deadlines. */
33
8
  export interface ConnectaDiscoveryConfig {
34
9
  /**
@@ -116,22 +91,22 @@ export interface ConnectaAdmissionConfig {
116
91
  code?: AdmissionPoolConfig;
117
92
  }
118
93
  /** Config-owned identity rules for one deployment and tenant. */
94
+ export type ConnectorPermission = "all" | "none" | readonly string[];
119
95
  export interface ConnectaIdentityConfig {
120
96
  /** Connector ids this admitted identity may discover and call. */
121
97
  connectorAccess?(identity: Readonly<AuthenticatedIdentity>): "all" | readonly string[] | Promise<"all" | readonly string[]>;
122
- /**
123
- * Whether a human may manage deployment access tokens and global activity.
124
- * Connector access already permits that human to manage the visible
125
- * connector's shared or personal auth. Omit to preserve the existing
126
- * all-interactive-humans operator rule.
127
- */
128
- operatorAccess?(principal: Readonly<IdentityReference>): boolean | Promise<boolean>;
98
+ /** Global payload-free activity reads. Defaults to interactive humans. */
99
+ activityAccess?(principal: Readonly<IdentityReference>): boolean | Promise<boolean>;
100
+ /** Shared credential and OAuth administration. Defaults to none. */
101
+ credentialAdministration?(identity: Readonly<AuthenticatedIdentity>): ConnectorPermission | Promise<ConnectorPermission>;
102
+ /** Connecting or changing the caller's personal account. Defaults to none. */
103
+ personalConnection?(identity: Readonly<AuthenticatedIdentity>): ConnectorPermission | Promise<ConnectorPermission>;
129
104
  }
130
105
  export interface ConnectaConfig {
131
106
  connectors: Connector[];
132
107
  /** Inbound auth adapters. Includes bearerToken(...); omit for open (dev). */
133
108
  auth?: InboundAuth | InboundAuth[];
134
- /** Identity-derived connector visibility and deployment operator membership. */
109
+ /** Code-derived connection visibility and independent management permissions. */
135
110
  identity?: ConnectaIdentityConfig;
136
111
  /** KVStorage impl. Defaults to memoryStorage(). */
137
112
  storage?: KVStorage;
@@ -140,15 +115,12 @@ export interface ConnectaConfig {
140
115
  * HTTPS URL also redirects matching inbound HTTP requests to HTTPS.
141
116
  */
142
117
  publicUrl?: string;
143
- /** Payload-free tool activity storage and operator-read policy. */
144
- activity?: ConnectaActivityConfig;
145
- /** Operator credential vault settings. */
146
- credentials?: ConnectaCredentialsConfig;
147
- /**
148
- * Named, revocable Bearer tokens for MCP clients. Creation and mutation
149
- * require an eligible interactive operator; token secrets are returned once.
150
- */
151
- accessTokens?: ConnectaAccessTokensConfig;
118
+ /** Optional recorder and reader, created by activityHistory() from /activity. */
119
+ activity?: ActivityModule;
120
+ /** Replaceable owner-partitioned credential storage. Omit for config-owned secrets. */
121
+ vault?: CredentialVault;
122
+ /** Optional connection UI, created by operatorUi() from /ui. */
123
+ ui?: OperatorSurface;
152
124
  /** Tool-catalog caching, persistence, stale fallback, and probe deadlines. */
153
125
  discovery?: ConnectaDiscoveryConfig;
154
126
  /** Deployment-wide call deadlines and result paging threshold. */
@@ -157,9 +129,8 @@ export interface ConnectaConfig {
157
129
  execute?: ConnectaExecuteConfig;
158
130
  /** Bounded MCP and fallback code-mode admission. */
159
131
  admission?: ConnectaAdmissionConfig;
160
- /** Optional browser UI and OAuth result-page labels. */
161
- branding?: ConnectaBranding;
162
- logger?: Logger;
132
+ /** Diagnostic output. Use "silent" to disable all diagnostic logging. */
133
+ logger?: Logger | "silent";
163
134
  serverInfo?: {
164
135
  name?: string;
165
136
  version?: string;
@@ -198,14 +169,10 @@ export { ConnectorCallError } from "./errors.js";
198
169
  export type { ConnectorCallErrorCode, CallErrorDetails } from "./errors.js";
199
170
  export { validateToolInput } from "./validate.js";
200
171
  export type { ValidateToolInputOptions } from "./validate.js";
201
- export { bearerToken } from "./auth/bearer.js";
202
- export type { BearerTokenOptions } from "./auth/bearer.js";
203
- export type { AccessTokenMetadata, CreatedAccessToken, } from "./access-tokens.js";
204
172
  export { memoryStorage } from "./storage/memory.js";
205
173
  export { CONNECTA_VERSION } from "./version.js";
206
174
  export type { Registry } from "./registry.js";
207
175
  export type { RemoteMcpOptions, RemoteMcpAuth, RemoteMcpRedirectPolicy, } from "./connectors/remote-mcp.js";
208
176
  export type { ApiOptions, ApiTool } from "./connectors/api.js";
209
- export type { CatalogDriftCounts, CatalogDriftReport, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectaBranding, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
177
+ export type { CatalogDriftCounts, CatalogDriftReport, ConnectaBranding, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
210
178
  export type { ActivityActor, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, CatalogDriftActivityEvent, ToolCallActivityEvent, } from "./activity.js";
211
- export { InvalidActivityCursorError } from "./activity.js";