@fungi.computer/veil 0.4.0 → 0.6.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 (43) hide show
  1. package/README.md +48 -54
  2. package/dist/best-effort-cleanup.d.ts +1 -1
  3. package/dist/connections/cleanup.d.ts +21 -0
  4. package/dist/connections/cleanup.js +66 -0
  5. package/dist/connections/contract.d.ts +192 -7
  6. package/dist/connections/contract.js +44 -2
  7. package/dist/connections/core.d.ts +58 -5
  8. package/dist/connections/core.js +438 -111
  9. package/dist/connections/discover.d.ts +3 -0
  10. package/dist/connections/discover.js +23 -0
  11. package/dist/connections/egress.js +3 -2
  12. package/dist/connections/index.d.ts +1 -0
  13. package/dist/connections/index.js +1 -0
  14. package/dist/connections/internal.d.ts +78 -0
  15. package/dist/connections/internal.js +66 -0
  16. package/dist/connections/mcp-agent.d.ts +37 -0
  17. package/dist/connections/mcp-agent.js +75 -0
  18. package/dist/connections/nango.d.ts +30 -0
  19. package/dist/connections/nango.js +179 -0
  20. package/dist/connections/oauth-flow.d.ts +83 -0
  21. package/dist/connections/oauth-flow.js +330 -0
  22. package/dist/connections/oauth-provider.d.ts +31 -0
  23. package/dist/connections/oauth-provider.js +96 -0
  24. package/dist/connections/oauth.d.ts +93 -0
  25. package/dist/connections/oauth.js +239 -0
  26. package/dist/connections/openapi.d.ts +36 -0
  27. package/dist/connections/openapi.js +120 -0
  28. package/dist/connections/sealed.js +23 -4
  29. package/dist/connections/source.d.ts +17 -0
  30. package/dist/connections/source.js +111 -0
  31. package/dist/connections/update.d.ts +41 -0
  32. package/dist/connections/update.js +81 -0
  33. package/dist/gatekeeper.d.ts +43 -85
  34. package/dist/gatekeeper.js +138 -95
  35. package/dist/github-app.d.ts +44 -0
  36. package/dist/github-app.js +93 -0
  37. package/dist/index.d.ts +0 -241
  38. package/dist/index.js +0 -256
  39. package/dist/nango.d.ts +40 -15
  40. package/dist/nango.js +7 -242
  41. package/package.json +15 -9
  42. package/dist/nango-git.d.ts +0 -19
  43. package/dist/nango-git.js +0 -125
package/dist/index.d.ts CHANGED
@@ -1,173 +1,3 @@
1
- import * as Schema from "effect/Schema";
2
- /** The repository identity selected by the Team, never by model input. */
3
- export declare const RepositoryScopeSchema: Schema.Struct<{
4
- readonly id: Schema.Number;
5
- readonly owner: Schema.NonEmptyString;
6
- readonly name: Schema.NonEmptyString;
7
- }>;
8
- export type RepositoryScope = Schema.Schema.Type<typeof RepositoryScopeSchema>;
9
- /** Bounded, credential-free metadata returned by the GitHub operation. */
10
- export declare const GitHubRepositorySchema: Schema.Struct<{
11
- readonly id: Schema.Number;
12
- readonly name: Schema.NonEmptyString;
13
- readonly fullName: Schema.NonEmptyString;
14
- readonly private: Schema.Boolean;
15
- readonly defaultBranch: Schema.NonEmptyString;
16
- }>;
17
- export type GitHubRepository = Schema.Schema.Type<typeof GitHubRepositorySchema>;
18
- export declare const ConnectInputSchema: Schema.Struct<{
19
- readonly requestId: Schema.NonEmptyString;
20
- readonly actorUserId: Schema.NonEmptyString;
21
- readonly holderAgentId: Schema.NonEmptyString;
22
- readonly repository: Schema.Struct<{
23
- readonly id: Schema.Number;
24
- readonly owner: Schema.NonEmptyString;
25
- readonly name: Schema.NonEmptyString;
26
- }>;
27
- }>;
28
- export type ConnectInput = Schema.Schema.Type<typeof ConnectInputSchema>;
29
- export declare const AttemptSchema: Schema.Struct<{
30
- readonly teamId: Schema.NonEmptyString;
31
- readonly attemptId: Schema.NonEmptyString;
32
- readonly connectionId: Schema.NonEmptyString;
33
- readonly integrationId: Schema.NonEmptyString;
34
- readonly expiresAt: Schema.Number;
35
- readonly requestId: Schema.NonEmptyString;
36
- readonly actorUserId: Schema.NonEmptyString;
37
- readonly holderAgentId: Schema.NonEmptyString;
38
- readonly repository: Schema.Struct<{
39
- readonly id: Schema.Number;
40
- readonly owner: Schema.NonEmptyString;
41
- readonly name: Schema.NonEmptyString;
42
- }>;
43
- }>;
44
- export type ConnectionAttempt = Schema.Schema.Type<typeof AttemptSchema>;
45
- /** Custody correlation is independent of the resource receiving the Connection. */
46
- export type CustodyCorrelation = Pick<ConnectionAttempt, "teamId" | "attemptId" | "actorUserId" | "integrationId">;
47
- /** Produced only by a custodian's verified completion boundary. */
48
- export declare const CompletionSchema: Schema.Struct<{
49
- readonly teamId: Schema.NonEmptyString;
50
- readonly attemptId: Schema.NonEmptyString;
51
- readonly principalId: Schema.NonEmptyString;
52
- readonly integrationId: Schema.NonEmptyString;
53
- readonly locator: Schema.NonEmptyString;
54
- }>;
55
- export type VerifiedCompletion = Schema.Schema.Type<typeof CompletionSchema>;
56
- export declare const ConnectionReceiptSchema: Schema.Struct<{
57
- readonly requestId: Schema.NonEmptyString;
58
- readonly connectionId: Schema.NonEmptyString;
59
- readonly holderAgentId: Schema.NonEmptyString;
60
- readonly repository: Schema.Struct<{
61
- readonly id: Schema.Number;
62
- readonly owner: Schema.NonEmptyString;
63
- readonly name: Schema.NonEmptyString;
64
- }>;
65
- readonly authorityVersion: Schema.Number;
66
- readonly status: Schema.Literals<readonly ["active", "disconnected"]>;
67
- readonly cleanup: Schema.Literals<readonly ["none", "pending"]>;
68
- }>;
69
- export type ConnectionReceipt = Schema.Schema.Type<typeof ConnectionReceiptSchema>;
70
- export declare const ReadBindingSchema: Schema.Struct<{
71
- readonly teamId: Schema.NonEmptyString;
72
- readonly holderAgentId: Schema.NonEmptyString;
73
- readonly connectionId: Schema.NonEmptyString;
74
- readonly repositoryId: Schema.Number;
75
- }>;
76
- export type ReadBinding = Schema.Schema.Type<typeof ReadBindingSchema>;
77
- export declare const DisconnectInputSchema: Schema.Struct<{
78
- readonly requestId: Schema.NonEmptyString;
79
- readonly actorUserId: Schema.NonEmptyString;
80
- readonly connectionId: Schema.NonEmptyString;
81
- }>;
82
- export type DisconnectInput = Schema.Schema.Type<typeof DisconnectInputSchema>;
83
- /** Private to the Team owner and its trusted custodian adapter. */
84
- export type RepositoryAccess = Readonly<{
85
- locator: string;
86
- repository: RepositoryScope;
87
- }>;
88
- export type PreparedCompletion = Readonly<{
89
- status: "pending";
90
- attempt: ConnectionAttempt;
91
- }> | Readonly<{
92
- status: "completed";
93
- receipt: ConnectionReceipt;
94
- }>;
95
- /** Why a verified completion's Nango connection is not held by the Team. */
96
- export type OrphanCode = "expired" | "denied" | "conflict" | "reconnect_required";
97
- /** A verified completion is held (completed), still activatable (pending), or an
98
- * orphan whose external connection the Team will never hold. */
99
- export type CompletionDecision = PreparedCompletion | Readonly<{
100
- status: "orphaned";
101
- code: OrphanCode;
102
- }>;
103
- /** Terminal custodian evidence that the held credential no longer works. */
104
- export type ReconnectReason = "refresh_failed" | "provider_unauthorized";
105
- export type ReconnectOutcome = Readonly<{
106
- status: "reconnect_required";
107
- connectionId: string;
108
- }> | Readonly<{
109
- status: "not_held";
110
- }>;
111
- /** Signed Nango auth webhooks this Team handles; every other operation is refused. */
112
- export type VerifiedWebhook = Readonly<{
113
- operation: "creation" | "refresh_failed";
114
- completion: VerifiedCompletion;
115
- }>;
116
- export type CleanupWork = Readonly<{
117
- connectionId: string;
118
- authorityVersion: number;
119
- locator: string;
120
- }>;
121
- declare const completionLookupSchema: Schema.Union<readonly [Schema.Struct<{
122
- readonly status: Schema.Literal<"unresolved">;
123
- }>, Schema.Struct<{
124
- readonly status: Schema.Literal<"ambiguous">;
125
- }>, Schema.Struct<{
126
- readonly status: Schema.Literal<"verified">;
127
- readonly completion: Schema.Struct<{
128
- readonly teamId: Schema.NonEmptyString;
129
- readonly attemptId: Schema.NonEmptyString;
130
- readonly principalId: Schema.NonEmptyString;
131
- readonly integrationId: Schema.NonEmptyString;
132
- readonly locator: Schema.NonEmptyString;
133
- }>;
134
- }>]>;
135
- /** Private Team operations. Mutations may await the native SQL+wake commit. */
136
- export type TeamConnectionsOwner = Readonly<{
137
- begin: (input: ConnectInput) => PreparedCompletion;
138
- readAttempt: (input: ConnectInput) => PreparedCompletion;
139
- prepareCompletion: (input: VerifiedCompletion) => CompletionDecision;
140
- /** Records the settled external deletion of a connection the Team never held. */
141
- recordOrphan: (input: VerifiedCompletion, code: OrphanCode, custody: "deleted" | "absent") => void;
142
- /** Marks the active Connection holding this locator as needing reconnection. */
143
- requireReconnect: (locator: string, reason: ReconnectReason) => ReconnectOutcome;
144
- activate: (input: VerifiedCompletion, repository: GitHubRepository) => ConnectionReceipt | Promise<ConnectionReceipt>;
145
- authorize: (binding: ReadBinding) => RepositoryAccess;
146
- disconnect: (input: DisconnectInput) => ConnectionReceipt | Promise<ConnectionReceipt>;
147
- nextCleanup: () => CleanupWork | undefined;
148
- acknowledgeCleanup: (work: CleanupWork) => void;
149
- }>;
150
- /** Ordinary Promise port. Only this trusted edge touches external custody. */
151
- export type CredentialCustodian = Readonly<{
152
- openSession: (input: Readonly<{
153
- teamId: string;
154
- attemptId: string;
155
- principalId: string;
156
- integrationId: string;
157
- }>, signal: AbortSignal) => Promise<Readonly<{
158
- token: string;
159
- connectUrl: string;
160
- expiresAt: number;
161
- }>>;
162
- /** Connection creation only; refuses every other signed operation. */
163
- verifyCompletion: (rawBody: string, signature: string) => Promise<VerifiedCompletion>;
164
- verifyWebhook: (rawBody: string, signature: string) => Promise<VerifiedWebhook>;
165
- /** Verified means supported complete correlation, never an arbitrary list-page candidate. */
166
- findCompletion: (attempt: CustodyCorrelation, signal: AbortSignal) => Promise<Schema.Schema.Type<typeof completionLookupSchema>>;
167
- /** Only confirmed deletion or a specifically decoded missing-connection result settles cleanup. */
168
- deleteConnection: (locator: string, signal: AbortSignal) => Promise<"deleted" | "absent">;
169
- readRepository: (access: RepositoryAccess, signal: AbortSignal) => Promise<string>;
170
- }>;
171
1
  /** Sanitized public failure; an optional cause is retained internally only. */
172
2
  export declare class VeilError extends Error {
173
3
  readonly code: "denied" | "invalid_input" | "invalid_completion" | "invalid_response" | "conflict" | "ambiguous" | "expired" | "unavailable" | "github_not_configured" | "cancelled" | "reconnect_required" | "unsupported"
@@ -181,74 +11,3 @@ export declare class VeilError extends Error {
181
11
  /** The provider's rate limit refused this request; retry later. */
182
12
  | "rate_limited", cause?: unknown);
183
13
  }
184
- /** One Effect policy behind the ordinary connect and GitHub Gatekeeper calls. */
185
- export declare function createGitHubConnections(options: Readonly<{
186
- owner: TeamConnectionsOwner;
187
- custodian: CredentialCustodian;
188
- }>): {
189
- connect: (input: ConnectInput, signal?: AbortSignal) => Promise<Readonly<{
190
- status: "completed";
191
- receipt: ConnectionReceipt;
192
- }> | {
193
- token: string;
194
- connectUrl: string;
195
- expiresAt: number;
196
- status: "pending";
197
- attemptId: string;
198
- }>;
199
- /** The one entry for signed custodian webhooks: activation or reconnect evidence. */
200
- complete: (rawBody: string, signature: string, signal?: AbortSignal) => Promise<{
201
- readonly requestId: string;
202
- readonly connectionId: string;
203
- readonly holderAgentId: string;
204
- readonly repository: {
205
- readonly id: number;
206
- readonly owner: string;
207
- readonly name: string;
208
- };
209
- readonly authorityVersion: number;
210
- readonly status: "active" | "disconnected";
211
- readonly cleanup: "none" | "pending";
212
- } | ReconnectOutcome>;
213
- reconcile: (input: ConnectInput, signal?: AbortSignal) => Promise<Readonly<{
214
- status: "completed";
215
- receipt: ConnectionReceipt;
216
- }> | {
217
- status: "pending";
218
- attemptId: string;
219
- }>;
220
- /** One bounded host recovery call; durable pending work survives interrupted or uncertain deletion. */
221
- cleanupOne: (signal?: AbortSignal) => Promise<{
222
- status: "idle";
223
- connectionId?: never;
224
- authorityVersion?: never;
225
- custody?: never;
226
- } | {
227
- status: "completed";
228
- connectionId: string;
229
- authorityVersion: number;
230
- custody: "absent" | "deleted";
231
- }>;
232
- readRepository: (binding: ReadBinding, signal?: AbortSignal) => Promise<{
233
- id: number;
234
- name: string;
235
- fullName: string;
236
- private: boolean;
237
- defaultBranch: string;
238
- }>;
239
- disconnect: (input: DisconnectInput) => Promise<{
240
- readonly requestId: string;
241
- readonly connectionId: string;
242
- readonly holderAgentId: string;
243
- readonly repository: {
244
- readonly id: number;
245
- readonly owner: string;
246
- readonly name: string;
247
- };
248
- readonly authorityVersion: number;
249
- readonly status: "active" | "disconnected";
250
- readonly cleanup: "none" | "pending";
251
- }>;
252
- };
253
- export type GitHubConnections = ReturnType<typeof createGitHubConnections>;
254
- export {};
package/dist/index.js CHANGED
@@ -1,86 +1,3 @@
1
- import * as Cause from "effect/Cause";
2
- import * as Effect from "effect/Effect";
3
- import * as Exit from "effect/Exit";
4
- import * as Option from "effect/Option";
5
- import * as Schema from "effect/Schema";
6
- const text = Schema.NonEmptyString;
7
- const integer = Schema.Number.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0));
8
- /** The repository identity selected by the Team, never by model input. */
9
- export const RepositoryScopeSchema = Schema.Struct({
10
- id: integer.check(Schema.isGreaterThan(0)),
11
- owner: text,
12
- name: text,
13
- });
14
- /** Bounded, credential-free metadata returned by the GitHub operation. */
15
- export const GitHubRepositorySchema = Schema.Struct({
16
- id: integer.check(Schema.isGreaterThan(0)),
17
- name: text,
18
- fullName: text,
19
- private: Schema.Boolean,
20
- defaultBranch: text,
21
- });
22
- const providerRepositorySchema = Schema.Struct({
23
- id: GitHubRepositorySchema.fields.id,
24
- name: text,
25
- full_name: GitHubRepositorySchema.fields.fullName,
26
- private: Schema.Boolean,
27
- default_branch: text,
28
- });
29
- export const ConnectInputSchema = Schema.Struct({
30
- requestId: text,
31
- actorUserId: text,
32
- holderAgentId: text,
33
- repository: RepositoryScopeSchema,
34
- });
35
- export const AttemptSchema = Schema.Struct({
36
- ...ConnectInputSchema.fields,
37
- teamId: text,
38
- attemptId: text,
39
- connectionId: text,
40
- integrationId: text,
41
- expiresAt: integer,
42
- });
43
- /** Produced only by a custodian's verified completion boundary. */
44
- export const CompletionSchema = Schema.Struct({
45
- teamId: text,
46
- attemptId: text,
47
- principalId: text,
48
- integrationId: text,
49
- locator: text,
50
- });
51
- export const ConnectionReceiptSchema = Schema.Struct({
52
- requestId: text,
53
- connectionId: text,
54
- holderAgentId: text,
55
- repository: RepositoryScopeSchema,
56
- authorityVersion: integer,
57
- status: Schema.Literals(["active", "disconnected"]),
58
- cleanup: Schema.Literals(["none", "pending"]),
59
- });
60
- export const ReadBindingSchema = Schema.Struct({
61
- teamId: text,
62
- holderAgentId: text,
63
- connectionId: text,
64
- repositoryId: integer,
65
- });
66
- export const DisconnectInputSchema = Schema.Struct({
67
- requestId: text,
68
- actorUserId: text,
69
- connectionId: text,
70
- });
71
- const completionLookupSchema = Schema.Union([
72
- Schema.Struct({ status: Schema.Literal("unresolved") }),
73
- Schema.Struct({ status: Schema.Literal("ambiguous") }),
74
- Schema.Struct({
75
- status: Schema.Literal("verified"),
76
- completion: CompletionSchema,
77
- }),
78
- ]);
79
- const connectSessionSchema = Schema.Struct({
80
- token: text,
81
- connectUrl: Schema.String,
82
- expiresAt: integer,
83
- });
84
1
  /** Sanitized public failure; an optional cause is retained internally only. */
85
2
  export class VeilError extends Error {
86
3
  code;
@@ -92,176 +9,3 @@ export class VeilError extends Error {
92
9
  Object.defineProperty(this, "cause", { value: cause, enumerable: false });
93
10
  }
94
11
  }
95
- const orphanCodes = new Set([
96
- "expired",
97
- "denied",
98
- "conflict",
99
- "reconnect_required",
100
- ]);
101
- function failure(cause) {
102
- return new VeilError(cause instanceof VeilError ? cause.code : "unavailable");
103
- }
104
- function owned(operation) {
105
- return Effect.try({ try: operation, catch: failure });
106
- }
107
- function run(program, signal) {
108
- return Effect.runPromiseExit(program, signal === undefined ? undefined : { signal }).then((exit) => {
109
- if (Exit.isSuccess(exit))
110
- return exit.value;
111
- const error = Option.getOrUndefined(Cause.findErrorOption(exit.cause));
112
- throw (error ??
113
- new VeilError(Cause.hasInterrupts(exit.cause) ? "cancelled" : "unavailable"));
114
- });
115
- }
116
- /** One Effect policy behind the ordinary connect and GitHub Gatekeeper calls. */
117
- export function createGitHubConnections(options) {
118
- const { owner, custodian } = options;
119
- const repository = (access) => Effect.gen(function* () {
120
- const raw = yield* Effect.tryPromise({
121
- try: (signal) => custodian.readRepository(access, signal),
122
- catch: failure,
123
- });
124
- const result = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(providerRepositorySchema))(raw).pipe(Effect.mapError(() => new VeilError("invalid_response")));
125
- if (result.id !== access.repository.id)
126
- return yield* Effect.fail(new VeilError("denied"));
127
- return {
128
- id: result.id,
129
- name: result.name,
130
- fullName: result.full_name,
131
- private: result.private,
132
- defaultBranch: result.default_branch,
133
- };
134
- });
135
- /** Delete a verified connection the Team will never hold, then refuse it. */
136
- const release = (completion, code) => Effect.gen(function* () {
137
- const raw = yield* Effect.tryPromise({
138
- try: (signal) => custodian.deleteConnection(completion.locator, signal),
139
- catch: failure,
140
- });
141
- const custody = yield* Schema.decodeUnknownEffect(Schema.Literals(["deleted", "absent"]))(raw).pipe(Effect.mapError(() => new VeilError("invalid_response")));
142
- yield* owned(() => {
143
- owner.recordOrphan(completion, code, custody);
144
- });
145
- return yield* Effect.fail(new VeilError(code));
146
- });
147
- const activate = (verified) => Effect.gen(function* () {
148
- const completion = yield* Schema.decodeUnknownEffect(CompletionSchema)(verified).pipe(Effect.mapError(() => new VeilError("invalid_completion")));
149
- const prepared = yield* owned(() => owner.prepareCompletion(completion));
150
- if (prepared.status === "completed")
151
- return prepared.receipt;
152
- if (prepared.status === "orphaned")
153
- return yield* release(completion, prepared.code);
154
- const { attempt } = prepared;
155
- return yield* Effect.gen(function* () {
156
- const metadata = yield* repository({
157
- locator: completion.locator,
158
- repository: attempt.repository,
159
- });
160
- return yield* Effect.tryPromise({
161
- try: async () => owner.activate(completion, metadata),
162
- catch: failure,
163
- });
164
- }).pipe(Effect.catchIf((error) => orphanCodes.has(error.code), (error) => Effect.gen(function* () {
165
- // A concurrent delivery of this same completion may have won.
166
- const settled = yield* owned(() => owner.prepareCompletion(completion));
167
- if (settled.status === "completed")
168
- return settled.receipt;
169
- return yield* release(completion, error.code);
170
- })));
171
- });
172
- return {
173
- connect: (input, signal) => run(Effect.gen(function* () {
174
- const command = yield* Schema.decodeUnknownEffect(ConnectInputSchema)(input).pipe(Effect.mapError(() => new VeilError("invalid_input")));
175
- const prepared = yield* owned(() => owner.begin(command));
176
- if (prepared.status === "completed")
177
- return prepared;
178
- const { attempt } = prepared;
179
- const rawSession = yield* Effect.tryPromise({
180
- try: (control) => custodian.openSession({
181
- teamId: attempt.teamId,
182
- attemptId: attempt.attemptId,
183
- principalId: attempt.actorUserId,
184
- integrationId: attempt.integrationId,
185
- }, control),
186
- catch: failure,
187
- });
188
- const session = yield* Schema.decodeUnknownEffect(connectSessionSchema)(rawSession).pipe(Effect.mapError(() => new VeilError("invalid_response")));
189
- return {
190
- status: "pending",
191
- attemptId: attempt.attemptId,
192
- ...session,
193
- };
194
- }), signal),
195
- /** The one entry for signed custodian webhooks: activation or reconnect evidence. */
196
- complete: (rawBody, signature, signal) => run(Effect.gen(function* () {
197
- const event = yield* Effect.tryPromise({
198
- try: () => custodian.verifyWebhook(rawBody, signature),
199
- catch: failure,
200
- });
201
- if (event.operation === "creation")
202
- return yield* activate(event.completion);
203
- const completion = yield* Schema.decodeUnknownEffect(CompletionSchema)(event.completion).pipe(Effect.mapError(() => new VeilError("invalid_completion")));
204
- const prepared = yield* owned(() => owner.prepareCompletion(completion));
205
- if (prepared.status !== "completed")
206
- return { status: "not_held" };
207
- return yield* owned(() => owner.requireReconnect(completion.locator, "refresh_failed"));
208
- }), signal),
209
- reconcile: (input, signal) => run(Effect.gen(function* () {
210
- const command = yield* Schema.decodeUnknownEffect(ConnectInputSchema)(input).pipe(Effect.mapError(() => new VeilError("invalid_input")));
211
- const prepared = yield* owned(() => owner.readAttempt(command));
212
- if (prepared.status === "completed")
213
- return prepared;
214
- const raw = yield* Effect.tryPromise({
215
- try: (control) => custodian.findCompletion(prepared.attempt, control),
216
- catch: failure,
217
- });
218
- const result = yield* Schema.decodeUnknownEffect(completionLookupSchema)(raw).pipe(Effect.mapError(() => new VeilError("invalid_response")));
219
- if (result.status === "ambiguous")
220
- return yield* Effect.fail(new VeilError("ambiguous"));
221
- if (result.status === "unresolved")
222
- return {
223
- status: "pending",
224
- attemptId: prepared.attempt.attemptId,
225
- };
226
- if (result.completion.attemptId !== prepared.attempt.attemptId)
227
- return yield* Effect.fail(new VeilError("invalid_completion"));
228
- const receipt = yield* activate(result.completion);
229
- return { status: "completed", receipt };
230
- }), signal),
231
- /** One bounded host recovery call; durable pending work survives interrupted or uncertain deletion. */
232
- cleanupOne: (signal) => run(Effect.gen(function* () {
233
- const work = yield* owned(() => owner.nextCleanup());
234
- if (work === undefined)
235
- return { status: "idle" };
236
- const raw = yield* Effect.tryPromise({
237
- try: (control) => custodian.deleteConnection(work.locator, control),
238
- catch: failure,
239
- });
240
- const custody = yield* Schema.decodeUnknownEffect(Schema.Literals(["deleted", "absent"]))(raw).pipe(Effect.mapError(() => new VeilError("invalid_response")));
241
- yield* owned(() => {
242
- owner.acknowledgeCleanup(work);
243
- });
244
- return {
245
- status: "completed",
246
- connectionId: work.connectionId,
247
- authorityVersion: work.authorityVersion,
248
- custody,
249
- };
250
- }), signal),
251
- readRepository: (binding, signal) => run(Effect.gen(function* () {
252
- const command = yield* Schema.decodeUnknownEffect(ReadBindingSchema)(binding).pipe(Effect.mapError(() => new VeilError("invalid_input")));
253
- // Admission is the fresh owner decision immediately before this one egress.
254
- const access = yield* owned(() => owner.authorize(command));
255
- return yield* repository(access).pipe(Effect.tapError((error) => error.code === "reconnect_required"
256
- ? owned(() => owner.requireReconnect(access.locator, "provider_unauthorized")).pipe(Effect.asVoid)
257
- : Effect.void));
258
- }), signal),
259
- disconnect: (input) => run(Effect.gen(function* () {
260
- const command = yield* Schema.decodeUnknownEffect(DisconnectInputSchema)(input).pipe(Effect.mapError(() => new VeilError("invalid_input")));
261
- return yield* Effect.tryPromise({
262
- try: async () => owner.disconnect(command),
263
- catch: failure,
264
- });
265
- })),
266
- };
267
- }
package/dist/nango.d.ts CHANGED
@@ -1,16 +1,41 @@
1
- import { type CredentialCustodian } from "./index.js";
2
- /** Trusted host configuration; never supplied by a model or Connect browser.
3
- * The public Connect document and API URLs are independent of the internal
4
- * serverUrl the Hub uses for custody. */
5
- export type NangoCustodianOptions = Readonly<{
6
- serverUrl: string;
7
- apiKey: string;
8
- webhookSigningKey: string;
9
- integrationId: string;
10
- connectBaseUrl: string;
11
- publicApiUrl: string;
12
- /** Deadline for one custodian request and its body; a miss is `unavailable`. */
13
- requestTimeoutMs?: number;
1
+ import * as Schema from "effect/Schema";
2
+ export declare const tagsSchema: Schema.Struct<{
3
+ readonly veil_team_id: Schema.NonEmptyString;
4
+ readonly veil_attempt_id: Schema.NonEmptyString;
5
+ readonly veil_principal_id: Schema.NonEmptyString;
14
6
  }>;
15
- /** Pinned Nango Connect/connection REST contract and maintained raw-body verifier. */
16
- export declare function createNangoCustodian(options: NangoCustodianOptions): CredentialCustodian;
7
+ export declare const sessionSchema: Schema.Struct<{
8
+ readonly data: Schema.Struct<{
9
+ readonly token: Schema.NonEmptyString;
10
+ readonly connect_link: Schema.NonEmptyString;
11
+ readonly expires_at: Schema.DateFromString;
12
+ }>;
13
+ }>;
14
+ export declare const webhookEnvelopeSchema: Schema.Struct<{
15
+ readonly type: Schema.NonEmptyString;
16
+ readonly operation: Schema.optional<Schema.NonEmptyString>;
17
+ }>;
18
+ /** Nango auth webhook fields shared by creation and refresh notifications. */
19
+ export declare const authWebhookSchema: Schema.Struct<{
20
+ readonly type: Schema.Literal<"auth">;
21
+ readonly operation: Schema.Literals<readonly ["creation", "refresh"]>;
22
+ readonly success: Schema.Boolean;
23
+ readonly connectionId: Schema.NonEmptyString;
24
+ readonly providerConfigKey: Schema.NonEmptyString;
25
+ readonly tags: Schema.Struct<{
26
+ readonly veil_team_id: Schema.NonEmptyString;
27
+ readonly veil_attempt_id: Schema.NonEmptyString;
28
+ readonly veil_principal_id: Schema.NonEmptyString;
29
+ }>;
30
+ readonly endUser: Schema.Struct<{
31
+ readonly endUserId: Schema.NonEmptyString;
32
+ readonly organizationId: Schema.NonEmptyString;
33
+ }>;
34
+ }>;
35
+ export declare function publicUrl(value: string): URL;
36
+ /** The Connect document handed to browsers: Nango's issued link, confined to
37
+ * the configured Connect UI and pinned to the configured public API. */
38
+ export declare function connectDocument(session: Readonly<{
39
+ token: string;
40
+ connectUrl: string;
41
+ }>, base: URL, api: URL): string;