@remnic/core 9.3.531 → 9.3.533
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/dist/access-cli.js +4 -4
- package/dist/access-http.d.ts +1 -1
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-service.d.ts +1 -1
- package/dist/bootstrap.d.ts +1 -1
- package/dist/{chunk-CWWMTTQE.js → chunk-6GUG4YNM.js} +44 -1
- package/dist/{chunk-CWWMTTQE.js.map → chunk-6GUG4YNM.js.map} +1 -1
- package/dist/{chunk-KAUXI453.js → chunk-KLZDGMDI.js} +2 -2
- package/dist/{chunk-KCLX6LOV.js → chunk-SRAF4TIS.js} +4 -4
- package/dist/{chunk-BECQDWBA.js → chunk-TQNRI55H.js} +35 -2
- package/dist/chunk-TQNRI55H.js.map +1 -0
- package/dist/{chunk-QMYXNM4P.js → chunk-VU3SVYMA.js} +3 -3
- package/dist/{cli-CPe_2KB1.d.ts → cli-9pwA_PXm.d.ts} +1 -1
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +3 -3
- package/dist/{connectors-cli-DbTPNj2H.d.ts → connectors-cli-2iaQ5tX2.d.ts} +1 -1
- package/dist/connectors-cli.d.ts +2 -2
- package/dist/explicit-capture.d.ts +1 -1
- package/dist/{framework-CyHYDcri.d.ts → framework-CNDn2164.d.ts} +24 -7
- package/dist/index.d.ts +4 -4
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/live-connectors-runner.js +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +1 -1
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +4 -4
- package/dist/{state-store-4QZISH3J.js → state-store-Z3EN56O5.js} +2 -2
- package/package.json +1 -1
- package/src/connectors/live/framework.ts +71 -6
- package/src/connectors/live/github.ts +10 -0
- package/src/connectors/live/gmail.ts +10 -0
- package/src/connectors/live/google-drive.ts +12 -4
- package/src/connectors/live/index.ts +2 -0
- package/src/connectors/live/live-connectors.test.ts +141 -0
- package/src/connectors/live/notion.ts +8 -0
- package/src/index.ts +2 -0
- package/dist/chunk-BECQDWBA.js.map +0 -1
- /package/dist/{chunk-KAUXI453.js.map → chunk-KLZDGMDI.js.map} +0 -0
- /package/dist/{chunk-KCLX6LOV.js.map → chunk-SRAF4TIS.js.map} +0 -0
- /package/dist/{chunk-QMYXNM4P.js.map → chunk-VU3SVYMA.js.map} +0 -0
- /package/dist/{state-store-4QZISH3J.js.map → state-store-Z3EN56O5.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LiveConnector, C as ConnectorConfig, a as ConnectorDocument } from './framework-
|
|
1
|
+
import { L as LiveConnector, C as ConnectorConfig, a as ConnectorDocument } from './framework-CNDn2164.js';
|
|
2
2
|
import { LiveConnectorsConfig } from './types.js';
|
|
3
3
|
import './types-BliCnURB.js';
|
|
4
4
|
import './index-DJ9QWMw-.js';
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
builtInLiveConnectorDefinitions,
|
|
3
3
|
hasEnabledLiveConnector,
|
|
4
4
|
runLiveConnectorsOnce
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-VU3SVYMA.js";
|
|
6
|
+
import "./chunk-TQNRI55H.js";
|
|
7
|
+
import "./chunk-6GUG4YNM.js";
|
|
8
8
|
import "./chunk-OKTXM5H4.js";
|
|
9
9
|
import "./chunk-EYIEWJNI.js";
|
|
10
10
|
import "./chunk-JUC24CTX.js";
|
|
@@ -31,7 +31,7 @@ import './local-llm.js';
|
|
|
31
31
|
import './fallback-llm.js';
|
|
32
32
|
import './resolve-provider-secret.js';
|
|
33
33
|
import './live-connectors-runner.js';
|
|
34
|
-
import './framework-
|
|
34
|
+
import './framework-CNDn2164.js';
|
|
35
35
|
import './relevance.js';
|
|
36
36
|
import './negative.js';
|
|
37
37
|
import './session-observer-state.js';
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ import './runtime/better-sqlite.js';
|
|
|
34
34
|
import 'better-sqlite3';
|
|
35
35
|
import './session-integrity.js';
|
|
36
36
|
import './resolve-provider-secret.js';
|
|
37
|
-
import './framework-
|
|
37
|
+
import './framework-CNDn2164.js';
|
|
38
38
|
import './memory-provenance.js';
|
|
39
39
|
import './user-model.js';
|
|
40
40
|
import './lcm/archive.js';
|
package/dist/orchestrator.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
sanitizeSessionKeyForFilename,
|
|
27
27
|
shouldFilterLifecycleRecallCandidate,
|
|
28
28
|
summarizeGraphShadowComparison
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-KLZDGMDI.js";
|
|
30
30
|
import "./chunk-Y2SXZ5KZ.js";
|
|
31
31
|
import "./chunk-BFBF3XEF.js";
|
|
32
32
|
import "./chunk-S53PKKWK.js";
|
|
@@ -69,7 +69,7 @@ import "./chunk-ZZTOURJI.js";
|
|
|
69
69
|
import "./chunk-XKXKSQU7.js";
|
|
70
70
|
import "./chunk-3GPTTA4J.js";
|
|
71
71
|
import "./chunk-IISBCCWR.js";
|
|
72
|
-
import "./chunk-
|
|
72
|
+
import "./chunk-VU3SVYMA.js";
|
|
73
73
|
import "./chunk-H63EDPFJ.js";
|
|
74
74
|
import "./chunk-PD6O7AXF.js";
|
|
75
75
|
import "./chunk-YAZNBMNF.js";
|
|
@@ -127,8 +127,8 @@ import "./chunk-HENLZHIT.js";
|
|
|
127
127
|
import "./chunk-7DTASS5T.js";
|
|
128
128
|
import "./chunk-KFY3SGN7.js";
|
|
129
129
|
import "./chunk-PCI747N2.js";
|
|
130
|
-
import "./chunk-
|
|
131
|
-
import "./chunk-
|
|
130
|
+
import "./chunk-TQNRI55H.js";
|
|
131
|
+
import "./chunk-6GUG4YNM.js";
|
|
132
132
|
import "./chunk-JXS5PDQ7.js";
|
|
133
133
|
import "./chunk-SKGV326D.js";
|
|
134
134
|
import "./chunk-BEUDU7Y4.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
readConnectorState,
|
|
11
11
|
withConnectorStateLock,
|
|
12
12
|
writeConnectorState
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-6GUG4YNM.js";
|
|
14
14
|
import "./chunk-EYIEWJNI.js";
|
|
15
15
|
import "./chunk-JUC24CTX.js";
|
|
16
16
|
import "./chunk-PZ5AY32C.js";
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
withConnectorStateLock,
|
|
28
28
|
writeConnectorState
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=state-store-
|
|
30
|
+
//# sourceMappingURL=state-store-Z3EN56O5.js.map
|
package/package.json
CHANGED
|
@@ -20,15 +20,61 @@
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Free-form connector configuration. Validated by each connector's
|
|
23
|
-
* `validateConfig` implementation
|
|
24
|
-
*
|
|
23
|
+
* `validateConfig` implementation and passed to `syncIncremental` for runtime
|
|
24
|
+
* use. MUST be JSON-serializable: no functions, no class instances, no
|
|
25
25
|
* circular references.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* Runtime configs may contain hydrated credentials. Do not persist a runtime
|
|
28
|
+
* config directly. Any code that needs to store connector settings must call
|
|
29
|
+
* `persistableConnectorConfig()` so credentials are stripped or replaced by
|
|
30
|
+
* connector-owned references.
|
|
29
31
|
*/
|
|
30
32
|
export type ConnectorConfig = Record<string, unknown>;
|
|
31
33
|
|
|
34
|
+
const DEFAULT_SECRET_KEY_PARTS = [
|
|
35
|
+
"token",
|
|
36
|
+
"secret",
|
|
37
|
+
"password",
|
|
38
|
+
"credential",
|
|
39
|
+
"apikey",
|
|
40
|
+
"accesskey",
|
|
41
|
+
"privatekey",
|
|
42
|
+
"authorization",
|
|
43
|
+
"authheader",
|
|
44
|
+
"cookie",
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Redact secret-looking keys from a JSON-serializable connector config.
|
|
49
|
+
* Built-in connectors provide explicit projections, but this default keeps
|
|
50
|
+
* third-party connectors from accidentally persisting obvious credentials.
|
|
51
|
+
*/
|
|
52
|
+
export function redactConnectorConfigSecrets(config: ConnectorConfig): ConnectorConfig {
|
|
53
|
+
return redactConnectorConfigValue(config) as ConnectorConfig;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function redactConnectorConfigValue(value: unknown): unknown {
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return value.map((item) => redactConnectorConfigValue(item));
|
|
59
|
+
}
|
|
60
|
+
if (typeof value !== "object" || value === null) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
const out: Record<string, unknown> = {};
|
|
64
|
+
for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {
|
|
65
|
+
if (isConnectorSecretConfigKey(key)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
out[key] = redactConnectorConfigValue(nested);
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isConnectorSecretConfigKey(key: string): boolean {
|
|
74
|
+
const normalized = key.replace(/[^a-z0-9]/giu, "").toLowerCase();
|
|
75
|
+
return DEFAULT_SECRET_KEY_PARTS.some((part) => normalized.includes(part));
|
|
76
|
+
}
|
|
77
|
+
|
|
32
78
|
/**
|
|
33
79
|
* Opaque cursor describing "where the last sync left off". Each connector
|
|
34
80
|
* defines what `kind` and `value` mean (e.g. Drive: `{kind: "pageToken",
|
|
@@ -135,11 +181,20 @@ export interface LiveConnector {
|
|
|
135
181
|
|
|
136
182
|
/**
|
|
137
183
|
* Validate raw user-supplied config. MUST throw on malformed input — never
|
|
138
|
-
* silently default. The returned object is
|
|
139
|
-
*
|
|
184
|
+
* silently default. The returned object is the runtime config passed back to
|
|
185
|
+
* `syncIncremental`; it may contain hydrated credentials and MUST NOT be
|
|
186
|
+
* persisted directly. Connectors SHOULD strip unknown fields.
|
|
140
187
|
*/
|
|
141
188
|
validateConfig(raw: unknown): ConnectorConfig;
|
|
142
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Return the subset of validated config that may be written to disk. Use this
|
|
192
|
+
* for state/config persistence instead of `validateConfig()`. Connectors that
|
|
193
|
+
* need credentials should omit the raw values here and store only non-secret
|
|
194
|
+
* scope/schedule fields plus any connector-owned secret references.
|
|
195
|
+
*/
|
|
196
|
+
persistConfig?(validated: ConnectorConfig): ConnectorConfig;
|
|
197
|
+
|
|
143
198
|
/**
|
|
144
199
|
* Run one incremental sync pass. See `SyncIncrementalArgs` /
|
|
145
200
|
* `SyncIncrementalResult` for the contract.
|
|
@@ -147,6 +202,16 @@ export interface LiveConnector {
|
|
|
147
202
|
syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult>;
|
|
148
203
|
}
|
|
149
204
|
|
|
205
|
+
export function persistableConnectorConfig(
|
|
206
|
+
connector: Pick<LiveConnector, "persistConfig">,
|
|
207
|
+
validated: ConnectorConfig,
|
|
208
|
+
): ConnectorConfig {
|
|
209
|
+
if (typeof connector.persistConfig === "function") {
|
|
210
|
+
return connector.persistConfig(validated);
|
|
211
|
+
}
|
|
212
|
+
return redactConnectorConfigSecrets(validated);
|
|
213
|
+
}
|
|
214
|
+
|
|
150
215
|
/**
|
|
151
216
|
* Regex enforcing the connector-id naming rule. Exported so connectors and
|
|
152
217
|
* tests can validate ids consistently with the registry.
|
|
@@ -514,6 +514,16 @@ export function createGitHubConnector(
|
|
|
514
514
|
return validateGitHubConfig(raw) as unknown as ConnectorConfig;
|
|
515
515
|
},
|
|
516
516
|
|
|
517
|
+
persistConfig(validated: ConnectorConfig): ConnectorConfig {
|
|
518
|
+
const config = validateGitHubConfig(validated);
|
|
519
|
+
return Object.freeze({
|
|
520
|
+
userLogin: config.userLogin,
|
|
521
|
+
repos: config.repos,
|
|
522
|
+
pollIntervalMs: config.pollIntervalMs,
|
|
523
|
+
includeDiscussions: config.includeDiscussions,
|
|
524
|
+
});
|
|
525
|
+
},
|
|
526
|
+
|
|
517
527
|
async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
|
|
518
528
|
const config = validateGitHubConfig(args.config);
|
|
519
529
|
throwIfAborted(args.abortSignal);
|
|
@@ -848,6 +848,16 @@ export function createGmailConnector(
|
|
|
848
848
|
return validateGmailConfig(raw) as unknown as ConnectorConfig;
|
|
849
849
|
},
|
|
850
850
|
|
|
851
|
+
persistConfig(validated: ConnectorConfig): ConnectorConfig {
|
|
852
|
+
const config = validateGmailConfig(validated);
|
|
853
|
+
return Object.freeze({
|
|
854
|
+
clientId: config.clientId,
|
|
855
|
+
userId: config.userId,
|
|
856
|
+
query: config.query,
|
|
857
|
+
pollIntervalMs: config.pollIntervalMs,
|
|
858
|
+
});
|
|
859
|
+
},
|
|
860
|
+
|
|
851
861
|
async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
|
|
852
862
|
const config = validateGmailConfig(args.config);
|
|
853
863
|
throwIfAborted(args.abortSignal);
|
|
@@ -397,14 +397,22 @@ export function createGoogleDriveConnector(
|
|
|
397
397
|
|
|
398
398
|
validateConfig(raw: unknown): ConnectorConfig {
|
|
399
399
|
// Cast to ConnectorConfig (Record<string, unknown>) per framework
|
|
400
|
-
// contract.
|
|
401
|
-
//
|
|
400
|
+
// contract. Persist only `persistConfig()` output; this runtime object
|
|
401
|
+
// carries hydrated credentials.
|
|
402
402
|
return validateGoogleDriveConfig(raw) as unknown as ConnectorConfig;
|
|
403
403
|
},
|
|
404
404
|
|
|
405
|
+
persistConfig(validated: ConnectorConfig): ConnectorConfig {
|
|
406
|
+
const config = validateGoogleDriveConfig(validated);
|
|
407
|
+
return Object.freeze({
|
|
408
|
+
clientId: config.clientId,
|
|
409
|
+
pollIntervalMs: config.pollIntervalMs,
|
|
410
|
+
folderIds: config.folderIds,
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
|
|
405
414
|
async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
|
|
406
|
-
// Re-validate on every pass:
|
|
407
|
-
// a JS caller could mutate it between passes.
|
|
415
|
+
// Re-validate on every pass: a JS caller could mutate it between passes.
|
|
408
416
|
const config = validateGoogleDriveConfig(args.config);
|
|
409
417
|
throwIfAborted(args.abortSignal);
|
|
410
418
|
|
|
@@ -6,6 +6,10 @@ import test from "node:test";
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
CONNECTOR_ID_PATTERN,
|
|
9
|
+
createGitHubConnector,
|
|
10
|
+
createGmailConnector,
|
|
11
|
+
createGoogleDriveConnector,
|
|
12
|
+
createNotionConnector,
|
|
9
13
|
type ConnectorConfig,
|
|
10
14
|
type ConnectorCursor,
|
|
11
15
|
type ConnectorDocument,
|
|
@@ -13,6 +17,8 @@ import {
|
|
|
13
17
|
type LiveConnector,
|
|
14
18
|
LiveConnectorRegistry,
|
|
15
19
|
LiveConnectorRegistryError,
|
|
20
|
+
persistableConnectorConfig,
|
|
21
|
+
redactConnectorConfigSecrets,
|
|
16
22
|
type SyncIncrementalArgs,
|
|
17
23
|
type SyncIncrementalResult,
|
|
18
24
|
isValidConnectorId,
|
|
@@ -21,6 +27,10 @@ import {
|
|
|
21
27
|
withConnectorStateLock,
|
|
22
28
|
writeConnectorState,
|
|
23
29
|
} from "./index.js";
|
|
30
|
+
import {
|
|
31
|
+
persistableConnectorConfig as persistableConnectorConfigFromRoot,
|
|
32
|
+
redactConnectorConfigSecrets as redactConnectorConfigSecretsFromRoot,
|
|
33
|
+
} from "../../index.js";
|
|
24
34
|
import {
|
|
25
35
|
_connectorStatePathForTest,
|
|
26
36
|
_refreshConnectorLockForTest,
|
|
@@ -122,6 +132,137 @@ test("CONNECTOR_ID_PATTERN matches isValidConnectorId", () => {
|
|
|
122
132
|
assert.ok(!CONNECTOR_ID_PATTERN.test("Drive"));
|
|
123
133
|
});
|
|
124
134
|
|
|
135
|
+
test("redactConnectorConfigSecrets removes nested secret-shaped keys", () => {
|
|
136
|
+
assert.deepEqual(
|
|
137
|
+
redactConnectorConfigSecrets({
|
|
138
|
+
endpoint: "https://example.invalid",
|
|
139
|
+
authorization: "Bearer synthetic-token",
|
|
140
|
+
authHeader: "Basic synthetic-credentials",
|
|
141
|
+
authorName: "kept",
|
|
142
|
+
nested: {
|
|
143
|
+
accessToken: "synthetic-token",
|
|
144
|
+
cookieHeader: "sid=synthetic-session",
|
|
145
|
+
publicLabel: "kept",
|
|
146
|
+
},
|
|
147
|
+
list: [
|
|
148
|
+
{ clientSecret: "synthetic-secret", sessionCookie: "synthetic-cookie", label: "kept" },
|
|
149
|
+
],
|
|
150
|
+
}),
|
|
151
|
+
{
|
|
152
|
+
endpoint: "https://example.invalid",
|
|
153
|
+
authorName: "kept",
|
|
154
|
+
nested: {
|
|
155
|
+
publicLabel: "kept",
|
|
156
|
+
},
|
|
157
|
+
list: [{ label: "kept" }],
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("persisted-config helpers are exported from the package root", () => {
|
|
163
|
+
assert.equal(persistableConnectorConfigFromRoot, persistableConnectorConfig);
|
|
164
|
+
assert.equal(redactConnectorConfigSecretsFromRoot, redactConnectorConfigSecrets);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("built-in live connectors expose persistable config without credential material", () => {
|
|
168
|
+
const cases: Array<{
|
|
169
|
+
connector: LiveConnector;
|
|
170
|
+
raw: ConnectorConfig;
|
|
171
|
+
secretKeys: readonly string[];
|
|
172
|
+
secretValues: readonly string[];
|
|
173
|
+
expected: ConnectorConfig;
|
|
174
|
+
}> = [
|
|
175
|
+
{
|
|
176
|
+
connector: createGitHubConnector(),
|
|
177
|
+
raw: {
|
|
178
|
+
token: "synthetic-github-token",
|
|
179
|
+
userLogin: "octocat",
|
|
180
|
+
repos: ["owner/repo"],
|
|
181
|
+
pollIntervalMs: 300_000,
|
|
182
|
+
includeDiscussions: true,
|
|
183
|
+
},
|
|
184
|
+
secretKeys: ["token"],
|
|
185
|
+
secretValues: ["synthetic-github-token"],
|
|
186
|
+
expected: {
|
|
187
|
+
userLogin: "octocat",
|
|
188
|
+
repos: ["owner/repo"],
|
|
189
|
+
pollIntervalMs: 300_000,
|
|
190
|
+
includeDiscussions: true,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
connector: createGmailConnector(),
|
|
195
|
+
raw: {
|
|
196
|
+
clientId: "synthetic-gmail-client-id",
|
|
197
|
+
clientSecret: "synthetic-gmail-client-secret",
|
|
198
|
+
refreshToken: "synthetic-gmail-refresh-token",
|
|
199
|
+
userId: "me",
|
|
200
|
+
query: "in:inbox",
|
|
201
|
+
pollIntervalMs: 300_000,
|
|
202
|
+
},
|
|
203
|
+
secretKeys: ["clientSecret", "refreshToken"],
|
|
204
|
+
secretValues: ["synthetic-gmail-client-secret", "synthetic-gmail-refresh-token"],
|
|
205
|
+
expected: {
|
|
206
|
+
clientId: "synthetic-gmail-client-id",
|
|
207
|
+
userId: "me",
|
|
208
|
+
query: "in:inbox",
|
|
209
|
+
pollIntervalMs: 300_000,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
connector: createGoogleDriveConnector(),
|
|
214
|
+
raw: {
|
|
215
|
+
clientId: "synthetic-drive-client-id",
|
|
216
|
+
clientSecret: "synthetic-drive-client-secret",
|
|
217
|
+
refreshToken: "synthetic-drive-refresh-token",
|
|
218
|
+
folderIds: ["folder_12345678"],
|
|
219
|
+
pollIntervalMs: 300_000,
|
|
220
|
+
},
|
|
221
|
+
secretKeys: ["clientSecret", "refreshToken"],
|
|
222
|
+
secretValues: ["synthetic-drive-client-secret", "synthetic-drive-refresh-token"],
|
|
223
|
+
expected: {
|
|
224
|
+
clientId: "synthetic-drive-client-id",
|
|
225
|
+
folderIds: ["folder_12345678"],
|
|
226
|
+
pollIntervalMs: 300_000,
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
connector: createNotionConnector(),
|
|
231
|
+
raw: {
|
|
232
|
+
token: "secret_synthetic-notion-token",
|
|
233
|
+
databaseIds: ["0123456789abcdef0123456789abcdef"],
|
|
234
|
+
pollIntervalMs: 300_000,
|
|
235
|
+
},
|
|
236
|
+
secretKeys: ["token"],
|
|
237
|
+
secretValues: ["secret_synthetic-notion-token"],
|
|
238
|
+
expected: {
|
|
239
|
+
databaseIds: ["0123456789abcdef0123456789abcdef"],
|
|
240
|
+
pollIntervalMs: 300_000,
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
for (const testCase of cases) {
|
|
246
|
+
const runtimeConfig = testCase.connector.validateConfig(testCase.raw);
|
|
247
|
+
for (const key of testCase.secretKeys) {
|
|
248
|
+
assert.ok(key in runtimeConfig, `${testCase.connector.id} runtime config should keep ${key}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const persisted = persistableConnectorConfig(testCase.connector, runtimeConfig);
|
|
252
|
+
assert.deepEqual(persisted, testCase.expected);
|
|
253
|
+
const persistedJson = JSON.stringify(persisted);
|
|
254
|
+
for (const key of testCase.secretKeys) {
|
|
255
|
+
assert.ok(!(key in persisted), `${testCase.connector.id} persisted config should omit ${key}`);
|
|
256
|
+
}
|
|
257
|
+
for (const value of testCase.secretValues) {
|
|
258
|
+
assert.ok(
|
|
259
|
+
!persistedJson.includes(value),
|
|
260
|
+
`${testCase.connector.id} persisted config leaked ${value}`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
125
266
|
// ───────────────────────────────────────────────────────────────────────────
|
|
126
267
|
// Registry
|
|
127
268
|
// ───────────────────────────────────────────────────────────────────────────
|
|
@@ -643,6 +643,14 @@ export function createNotionConnector(
|
|
|
643
643
|
return validateNotionConfig(raw) as unknown as ConnectorConfig;
|
|
644
644
|
},
|
|
645
645
|
|
|
646
|
+
persistConfig(validated: ConnectorConfig): ConnectorConfig {
|
|
647
|
+
const config = validateNotionConfig(validated);
|
|
648
|
+
return Object.freeze({
|
|
649
|
+
databaseIds: config.databaseIds,
|
|
650
|
+
pollIntervalMs: config.pollIntervalMs,
|
|
651
|
+
});
|
|
652
|
+
},
|
|
653
|
+
|
|
646
654
|
async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
|
|
647
655
|
const config = validateNotionConfig(args.config);
|
|
648
656
|
throwIfAborted(args.abortSignal);
|
package/src/index.ts
CHANGED
|
@@ -794,6 +794,8 @@ export { coerceInstallExtension } from "./connectors/coerce.js";
|
|
|
794
794
|
export {
|
|
795
795
|
CONNECTOR_ID_PATTERN,
|
|
796
796
|
isValidConnectorId,
|
|
797
|
+
persistableConnectorConfig,
|
|
798
|
+
redactConnectorConfigSecrets,
|
|
797
799
|
LiveConnectorRegistry,
|
|
798
800
|
LiveConnectorRegistryError,
|
|
799
801
|
listConnectorStates,
|