@mycreat-labs/integrations-sdk 0.0.0-stage → 0.1.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/README.md +54 -2
- package/dist/adapters/bullmq.cjs +110 -0
- package/dist/adapters/bullmq.cjs.map +1 -0
- package/dist/adapters/bullmq.d.cts +11 -0
- package/dist/adapters/bullmq.d.ts +11 -0
- package/dist/adapters/bullmq.js +85 -0
- package/dist/adapters/bullmq.js.map +1 -0
- package/dist/adapters/postgres.cjs +396 -0
- package/dist/adapters/postgres.cjs.map +1 -0
- package/dist/adapters/postgres.d.cts +51 -0
- package/dist/adapters/postgres.d.ts +51 -0
- package/dist/adapters/postgres.js +368 -0
- package/dist/adapters/postgres.js.map +1 -0
- package/dist/adapters/prisma.cjs +414 -0
- package/dist/adapters/prisma.cjs.map +1 -0
- package/dist/adapters/prisma.d.cts +15 -0
- package/dist/adapters/prisma.d.ts +15 -0
- package/dist/adapters/prisma.js +386 -0
- package/dist/adapters/prisma.js.map +1 -0
- package/dist/adapters/redis.cjs +125 -0
- package/dist/adapters/redis.cjs.map +1 -0
- package/dist/adapters/redis.d.cts +20 -0
- package/dist/adapters/redis.d.ts +20 -0
- package/dist/adapters/redis.js +98 -0
- package/dist/adapters/redis.js.map +1 -0
- package/dist/errors-3hDEtzuZ.d.cts +11 -0
- package/dist/errors-3hDEtzuZ.d.ts +11 -0
- package/dist/index.cjs +1328 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +128 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.js +1297 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/index.cjs +1287 -0
- package/dist/providers/index.cjs.map +1 -0
- package/dist/providers/index.d.cts +144 -0
- package/dist/providers/index.d.ts +144 -0
- package/dist/providers/index.js +1252 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/testing.cjs +275 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +20 -0
- package/dist/testing.d.ts +20 -0
- package/dist/testing.js +248 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-Y4-DoJ1A.d.cts +260 -0
- package/dist/types-Y4-DoJ1A.d.ts +260 -0
- package/docs/migration.md +23 -0
- package/docs/security.md +26 -0
- package/docs/verification.md +22 -0
- package/examples/embedded-host.ts +62 -0
- package/migrations/0001_initial.sql +40 -0
- package/package.json +90 -4
- package/schema.prisma +80 -0
package/dist/testing.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var IntegrationError = class extends Error {
|
|
3
|
+
constructor(code, disposition = "permanent_failure", retryAfterMs) {
|
|
4
|
+
super(code);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.disposition = disposition;
|
|
7
|
+
this.retryAfterMs = retryAfterMs;
|
|
8
|
+
this.name = "IntegrationError";
|
|
9
|
+
}
|
|
10
|
+
code;
|
|
11
|
+
disposition;
|
|
12
|
+
retryAfterMs;
|
|
13
|
+
sdkError = "@mycreat-labs/integrations-sdk/v1";
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/testing.ts
|
|
17
|
+
var key = (namespace, id) => `${namespace}\0${id}`;
|
|
18
|
+
var matches = (value, scope) => value.namespace === scope.namespace && value.ownerId === scope.ownerId;
|
|
19
|
+
function createTestStore() {
|
|
20
|
+
let data = {
|
|
21
|
+
owners: /* @__PURE__ */ new Map(),
|
|
22
|
+
flows: /* @__PURE__ */ new Map(),
|
|
23
|
+
grants: /* @__PURE__ */ new Map(),
|
|
24
|
+
connections: /* @__PURE__ */ new Map(),
|
|
25
|
+
operations: /* @__PURE__ */ new Map(),
|
|
26
|
+
events: /* @__PURE__ */ new Map()
|
|
27
|
+
};
|
|
28
|
+
let tail = Promise.resolve();
|
|
29
|
+
const store = {
|
|
30
|
+
async assertCompatible() {
|
|
31
|
+
},
|
|
32
|
+
snapshot: () => structuredClone(data),
|
|
33
|
+
async transaction(work) {
|
|
34
|
+
let release;
|
|
35
|
+
const previous = tail;
|
|
36
|
+
tail = new Promise((resolve) => {
|
|
37
|
+
release = resolve;
|
|
38
|
+
});
|
|
39
|
+
await previous;
|
|
40
|
+
const draft = structuredClone(data);
|
|
41
|
+
const tx = {
|
|
42
|
+
nativeContext: { testTransaction: true },
|
|
43
|
+
async lockScope(scope, allowErased = false) {
|
|
44
|
+
const id = key(scope.namespace, scope.ownerId);
|
|
45
|
+
if (!draft.owners.has(id))
|
|
46
|
+
draft.owners.set(id, { erased: false, epochs: {} });
|
|
47
|
+
if (draft.owners.get(id).erased && !allowErased)
|
|
48
|
+
throw new IntegrationError("owner_erased");
|
|
49
|
+
return draft.owners.get(id).erased;
|
|
50
|
+
},
|
|
51
|
+
async authorizationEpoch(scope, epochKey, advance = false) {
|
|
52
|
+
const owner = draft.owners.get(key(scope.namespace, scope.ownerId));
|
|
53
|
+
if (!owner) throw new Error("owner_not_locked");
|
|
54
|
+
if (advance)
|
|
55
|
+
owner.epochs[epochKey] = (owner.epochs[epochKey] ?? 0) + 1;
|
|
56
|
+
return owner.epochs[epochKey] ?? 0;
|
|
57
|
+
},
|
|
58
|
+
async markOwnerErased(scope) {
|
|
59
|
+
const owner = draft.owners.get(key(scope.namespace, scope.ownerId));
|
|
60
|
+
if (owner) owner.erased = true;
|
|
61
|
+
},
|
|
62
|
+
async assertAccountOwner(scope, provider, registrationId, accountId) {
|
|
63
|
+
if ([...draft.connections.values()].some(
|
|
64
|
+
(c) => c.namespace === scope.namespace && c.ownerId !== scope.ownerId && c.provider === provider && c.registrationId === registrationId && c.account.id === accountId
|
|
65
|
+
))
|
|
66
|
+
throw new IntegrationError("account_already_connected");
|
|
67
|
+
},
|
|
68
|
+
async collectGarbage(namespace, now, retentionMs) {
|
|
69
|
+
for (const [id, flow] of draft.flows)
|
|
70
|
+
if (flow.namespace === namespace && flow.expiresAt <= now)
|
|
71
|
+
draft.flows.delete(id);
|
|
72
|
+
for (const [id, op] of draft.operations)
|
|
73
|
+
if (op.namespace === namespace && op.action !== "__sdk.revoke" && ["failed", "blocked", "outcome_unknown", "cancelled"].includes(
|
|
74
|
+
op.status
|
|
75
|
+
) && op.updatedAt <= now - retentionMs)
|
|
76
|
+
draft.operations.set(id, {
|
|
77
|
+
...op,
|
|
78
|
+
input: { keyId: "", value: "" },
|
|
79
|
+
hostContext: void 0,
|
|
80
|
+
status: "failed",
|
|
81
|
+
errorCode: "payload_expired",
|
|
82
|
+
version: op.version + 1
|
|
83
|
+
});
|
|
84
|
+
for (const [id, grant] of draft.grants)
|
|
85
|
+
if (grant.namespace === namespace && grant.status === "revoked" && ![...draft.connections.values()].some(
|
|
86
|
+
(c) => c.namespace === namespace && c.grantId === grant.id
|
|
87
|
+
))
|
|
88
|
+
draft.grants.delete(id);
|
|
89
|
+
},
|
|
90
|
+
async insertFlow(value) {
|
|
91
|
+
draft.flows.set(key(value.namespace, value.id), value);
|
|
92
|
+
},
|
|
93
|
+
async consumeFlow(namespace, id, bindingHash, purpose, now) {
|
|
94
|
+
const idKey = key(namespace, id);
|
|
95
|
+
const value = draft.flows.get(idKey);
|
|
96
|
+
if (!value || value.bindingHash !== bindingHash || value.purpose !== purpose || value.expiresAt <= now)
|
|
97
|
+
return null;
|
|
98
|
+
draft.flows.delete(idKey);
|
|
99
|
+
return value;
|
|
100
|
+
},
|
|
101
|
+
async insertGrant(value) {
|
|
102
|
+
draft.grants.set(key(value.namespace, value.id), value);
|
|
103
|
+
},
|
|
104
|
+
async getGrant(scope, id) {
|
|
105
|
+
const value = draft.grants.get(key(scope.namespace, id));
|
|
106
|
+
return value && matches(value, scope) ? value : null;
|
|
107
|
+
},
|
|
108
|
+
async saveGrant(value, expected) {
|
|
109
|
+
const id = key(value.namespace, value.id);
|
|
110
|
+
if (draft.grants.get(id)?.version !== expected) return false;
|
|
111
|
+
draft.grants.set(id, value);
|
|
112
|
+
return true;
|
|
113
|
+
},
|
|
114
|
+
async insertConnection(value) {
|
|
115
|
+
if ([...draft.connections.values()].some(
|
|
116
|
+
(c) => matches(c, value) && c.provider === value.provider && c.registrationId === value.registrationId && c.account.id === value.account.id
|
|
117
|
+
))
|
|
118
|
+
throw new Error("unique_connection");
|
|
119
|
+
draft.connections.set(key(value.namespace, value.id), value);
|
|
120
|
+
},
|
|
121
|
+
async getConnection(scope, id) {
|
|
122
|
+
const value = draft.connections.get(key(scope.namespace, id));
|
|
123
|
+
return value && matches(value, scope) ? value : null;
|
|
124
|
+
},
|
|
125
|
+
async listConnections(scope) {
|
|
126
|
+
return [...draft.connections.values()].filter(
|
|
127
|
+
(v) => matches(v, scope)
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
async saveConnection(value, expected) {
|
|
131
|
+
const id = key(value.namespace, value.id);
|
|
132
|
+
if (draft.connections.get(id)?.generation !== expected) return false;
|
|
133
|
+
draft.connections.set(id, value);
|
|
134
|
+
return true;
|
|
135
|
+
},
|
|
136
|
+
async insertOperation(value) {
|
|
137
|
+
const existing = [...draft.operations.values()].find(
|
|
138
|
+
(v) => matches(v, value) && v.action === value.action && v.idempotencyKey === value.idempotencyKey
|
|
139
|
+
);
|
|
140
|
+
if (existing) return existing;
|
|
141
|
+
draft.operations.set(key(value.namespace, value.id), value);
|
|
142
|
+
return value;
|
|
143
|
+
},
|
|
144
|
+
async getOperation(scope, id) {
|
|
145
|
+
const value = draft.operations.get(key(scope.namespace, id));
|
|
146
|
+
return value && matches(value, scope) ? value : null;
|
|
147
|
+
},
|
|
148
|
+
async listOperations(scope, connectionId) {
|
|
149
|
+
return [...draft.operations.values()].filter(
|
|
150
|
+
(v) => matches(v, scope) && (!connectionId || v.connectionId === connectionId)
|
|
151
|
+
);
|
|
152
|
+
},
|
|
153
|
+
async hasPendingRevocation(scope, connectionId) {
|
|
154
|
+
return [...draft.operations.values()].some(
|
|
155
|
+
(op) => matches(op, scope) && op.connectionId === connectionId && op.action === "__sdk.revoke" && !["succeeded", "cancelled"].includes(op.status)
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
async saveOperation(value, expected, lease) {
|
|
159
|
+
const id = key(value.namespace, value.id);
|
|
160
|
+
const current = draft.operations.get(id);
|
|
161
|
+
if (current?.version !== expected || lease && (current.leaseToken !== lease || (current.leaseUntil ?? 0) <= Date.now()))
|
|
162
|
+
return false;
|
|
163
|
+
draft.operations.set(id, value);
|
|
164
|
+
return true;
|
|
165
|
+
},
|
|
166
|
+
async claimOperation(namespace, id, version, now, leaseToken, leaseUntil) {
|
|
167
|
+
const idKey = key(namespace, id);
|
|
168
|
+
const current = draft.operations.get(idKey);
|
|
169
|
+
if (!current || current.version !== version || !["pending", "outcome_unknown"].includes(current.status) || current.availableAt > now)
|
|
170
|
+
return null;
|
|
171
|
+
const next = {
|
|
172
|
+
...current,
|
|
173
|
+
status: "running",
|
|
174
|
+
version: current.version + 1,
|
|
175
|
+
attempts: current.attempts + 1,
|
|
176
|
+
leaseToken,
|
|
177
|
+
leaseUntil,
|
|
178
|
+
updatedAt: now
|
|
179
|
+
};
|
|
180
|
+
draft.operations.set(idKey, next);
|
|
181
|
+
return next;
|
|
182
|
+
},
|
|
183
|
+
async dueOperations(namespace, now, limit) {
|
|
184
|
+
return [...draft.operations.values()].filter(
|
|
185
|
+
(v) => v.namespace === namespace && ["pending", "outcome_unknown"].includes(v.status) && v.availableAt <= now
|
|
186
|
+
).slice(0, limit).map((v) => ({ id: v.id, version: v.version }));
|
|
187
|
+
},
|
|
188
|
+
async recoverOperations(namespace, now) {
|
|
189
|
+
let count = 0;
|
|
190
|
+
for (const [id, value] of draft.operations)
|
|
191
|
+
if (value.namespace === namespace && value.status === "running" && (value.leaseUntil ?? 0) <= now) {
|
|
192
|
+
draft.operations.set(id, {
|
|
193
|
+
...value,
|
|
194
|
+
status: value.dispatching ? "outcome_unknown" : "pending",
|
|
195
|
+
version: value.version + 1,
|
|
196
|
+
availableAt: now,
|
|
197
|
+
leaseToken: void 0,
|
|
198
|
+
leaseUntil: void 0
|
|
199
|
+
});
|
|
200
|
+
count++;
|
|
201
|
+
}
|
|
202
|
+
return count;
|
|
203
|
+
},
|
|
204
|
+
async insertEvent(value) {
|
|
205
|
+
draft.events.set(key(value.namespace, value.id), value);
|
|
206
|
+
},
|
|
207
|
+
async listEvents(scope, after) {
|
|
208
|
+
const values = [...draft.events.values()].filter(
|
|
209
|
+
(v) => matches(v, scope)
|
|
210
|
+
);
|
|
211
|
+
const at = after ? values.findIndex((v) => v.id === after) : -1;
|
|
212
|
+
return values.slice(at + 1);
|
|
213
|
+
},
|
|
214
|
+
async eraseOwner(scope, preserve) {
|
|
215
|
+
for (const [id, value] of draft.flows)
|
|
216
|
+
if (matches(value, scope)) draft.flows.delete(id);
|
|
217
|
+
for (const [id, value] of draft.events)
|
|
218
|
+
if (matches(value, scope)) draft.events.delete(id);
|
|
219
|
+
for (const [id, value] of draft.operations)
|
|
220
|
+
if (matches(value, scope) && (!preserve || value.action !== "__sdk.revoke" || ["succeeded", "cancelled"].includes(value.status)))
|
|
221
|
+
draft.operations.delete(id);
|
|
222
|
+
for (const [id, value] of draft.connections)
|
|
223
|
+
if (matches(value, scope) && (!preserve || ![...draft.operations.values()].some(
|
|
224
|
+
(op) => op.connectionId === value.id && matches(op, scope)
|
|
225
|
+
)))
|
|
226
|
+
draft.connections.delete(id);
|
|
227
|
+
for (const [id, value] of draft.grants)
|
|
228
|
+
if (matches(value, scope) && (!preserve || ![...draft.connections.values()].some(
|
|
229
|
+
(c) => c.grantId === value.id && matches(c, scope)
|
|
230
|
+
)))
|
|
231
|
+
draft.grants.delete(id);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
try {
|
|
235
|
+
const result = await work(tx);
|
|
236
|
+
data = draft;
|
|
237
|
+
return result;
|
|
238
|
+
} finally {
|
|
239
|
+
release();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
return store;
|
|
244
|
+
}
|
|
245
|
+
export {
|
|
246
|
+
createTestStore
|
|
247
|
+
};
|
|
248
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/testing.ts"],"sourcesContent":["export type FailureDisposition =\n \"retryable\" | \"requires_reauth\" | \"outcome_unknown\" | \"permanent_failure\";\nexport class IntegrationError extends Error {\n readonly sdkError = \"@mycreat-labs/integrations-sdk/v1\";\n constructor(\n readonly code: string,\n readonly disposition: FailureDisposition = \"permanent_failure\",\n readonly retryAfterMs?: number,\n ) {\n super(code);\n this.name = \"IntegrationError\";\n }\n}\nexport function integrationError(error: unknown): IntegrationError {\n if (error instanceof IntegrationError) return error;\n // Bundled subpath entries and independently installed copies have separate class identities.\n if (\n error instanceof Error &&\n \"sdkError\" in error &&\n error.sdkError === \"@mycreat-labs/integrations-sdk/v1\" &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n /^[a-zA-Z0-9_]{1,100}$/.test(error.code) &&\n \"disposition\" in error &&\n [\n \"retryable\",\n \"requires_reauth\",\n \"outcome_unknown\",\n \"permanent_failure\",\n ].includes(String(error.disposition))\n ) {\n const delay =\n \"retryAfterMs\" in error &&\n typeof error.retryAfterMs === \"number\" &&\n Number.isFinite(error.retryAfterMs) &&\n error.retryAfterMs >= 0\n ? error.retryAfterMs\n : undefined;\n return new IntegrationError(\n error.code,\n error.disposition as FailureDisposition,\n delay,\n );\n }\n return new IntegrationError(\"provider_unavailable\", \"outcome_unknown\");\n}\n","/** Test-only in-memory transactional adapter. Import explicitly from /testing; never a production default. */\nimport type {\n Connection,\n Flow,\n Grant,\n IntegrationEvent,\n IntegrationStore,\n IntegrationTransaction,\n Operation,\n Scope,\n} from \"./types\";\nimport { IntegrationError } from \"./errors\";\ntype Data = {\n owners: Map<string, { erased: boolean; epochs: Record<string, number> }>;\n flows: Map<string, Flow>;\n grants: Map<string, Grant>;\n connections: Map<string, Connection>;\n operations: Map<string, Operation>;\n events: Map<string, IntegrationEvent>;\n};\nconst key = (namespace: string, id: string) => `${namespace}\\0${id}`;\nconst matches = (value: { namespace: string; ownerId: string }, scope: Scope) =>\n value.namespace === scope.namespace && value.ownerId === scope.ownerId;\nexport function createTestStore() {\n let data: Data = {\n owners: new Map(),\n flows: new Map(),\n grants: new Map(),\n connections: new Map(),\n operations: new Map(),\n events: new Map(),\n };\n let tail = Promise.resolve();\n const store: IntegrationStore & { snapshot: () => Data } = {\n async assertCompatible() {},\n snapshot: () => structuredClone(data),\n async transaction(work) {\n let release!: () => void;\n const previous = tail;\n tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n const draft = structuredClone(data);\n const tx: IntegrationTransaction = {\n nativeContext: { testTransaction: true },\n async lockScope(scope, allowErased = false) {\n const id = key(scope.namespace, scope.ownerId);\n if (!draft.owners.has(id))\n draft.owners.set(id, { erased: false, epochs: {} });\n if (draft.owners.get(id)!.erased && !allowErased)\n throw new IntegrationError(\"owner_erased\");\n return draft.owners.get(id)!.erased;\n },\n async authorizationEpoch(scope, epochKey, advance = false) {\n const owner = draft.owners.get(key(scope.namespace, scope.ownerId));\n if (!owner) throw new Error(\"owner_not_locked\");\n if (advance)\n owner.epochs[epochKey] = (owner.epochs[epochKey] ?? 0) + 1;\n return owner.epochs[epochKey] ?? 0;\n },\n async markOwnerErased(scope) {\n const owner = draft.owners.get(key(scope.namespace, scope.ownerId));\n if (owner) owner.erased = true;\n },\n async assertAccountOwner(scope, provider, registrationId, accountId) {\n if (\n [...draft.connections.values()].some(\n (c) =>\n c.namespace === scope.namespace &&\n c.ownerId !== scope.ownerId &&\n c.provider === provider &&\n c.registrationId === registrationId &&\n c.account.id === accountId,\n )\n )\n throw new IntegrationError(\"account_already_connected\");\n },\n async collectGarbage(namespace, now, retentionMs) {\n for (const [id, flow] of draft.flows)\n if (flow.namespace === namespace && flow.expiresAt <= now)\n draft.flows.delete(id);\n for (const [id, op] of draft.operations)\n if (\n op.namespace === namespace &&\n op.action !== \"__sdk.revoke\" &&\n [\"failed\", \"blocked\", \"outcome_unknown\", \"cancelled\"].includes(\n op.status,\n ) &&\n op.updatedAt <= now - retentionMs\n )\n draft.operations.set(id, {\n ...op,\n input: { keyId: \"\", value: \"\" },\n hostContext: undefined,\n status: \"failed\",\n errorCode: \"payload_expired\",\n version: op.version + 1,\n });\n for (const [id, grant] of draft.grants)\n if (\n grant.namespace === namespace &&\n grant.status === \"revoked\" &&\n ![...draft.connections.values()].some(\n (c) => c.namespace === namespace && c.grantId === grant.id,\n )\n )\n draft.grants.delete(id);\n },\n async insertFlow(value) {\n draft.flows.set(key(value.namespace, value.id), value);\n },\n async consumeFlow(namespace, id, bindingHash, purpose, now) {\n const idKey = key(namespace, id);\n const value = draft.flows.get(idKey);\n if (\n !value ||\n value.bindingHash !== bindingHash ||\n value.purpose !== purpose ||\n value.expiresAt <= now\n )\n return null;\n draft.flows.delete(idKey);\n return value;\n },\n async insertGrant(value) {\n draft.grants.set(key(value.namespace, value.id), value);\n },\n async getGrant(scope, id) {\n const value = draft.grants.get(key(scope.namespace, id));\n return value && matches(value, scope) ? value : null;\n },\n async saveGrant(value, expected) {\n const id = key(value.namespace, value.id);\n if (draft.grants.get(id)?.version !== expected) return false;\n draft.grants.set(id, value);\n return true;\n },\n async insertConnection(value) {\n if (\n [...draft.connections.values()].some(\n (c) =>\n matches(c, value) &&\n c.provider === value.provider &&\n c.registrationId === value.registrationId &&\n c.account.id === value.account.id,\n )\n )\n throw new Error(\"unique_connection\");\n draft.connections.set(key(value.namespace, value.id), value);\n },\n async getConnection(scope, id) {\n const value = draft.connections.get(key(scope.namespace, id));\n return value && matches(value, scope) ? value : null;\n },\n async listConnections(scope) {\n return [...draft.connections.values()].filter((v) =>\n matches(v, scope),\n );\n },\n async saveConnection(value, expected) {\n const id = key(value.namespace, value.id);\n if (draft.connections.get(id)?.generation !== expected) return false;\n draft.connections.set(id, value);\n return true;\n },\n async insertOperation(value) {\n const existing = [...draft.operations.values()].find(\n (v) =>\n matches(v, value) &&\n v.action === value.action &&\n v.idempotencyKey === value.idempotencyKey,\n );\n if (existing) return existing;\n draft.operations.set(key(value.namespace, value.id), value);\n return value;\n },\n async getOperation(scope, id) {\n const value = draft.operations.get(key(scope.namespace, id));\n return value && matches(value, scope) ? value : null;\n },\n async listOperations(scope, connectionId) {\n return [...draft.operations.values()].filter(\n (v) =>\n matches(v, scope) &&\n (!connectionId || v.connectionId === connectionId),\n );\n },\n async hasPendingRevocation(scope, connectionId) {\n return [...draft.operations.values()].some(\n (op) =>\n matches(op, scope) &&\n op.connectionId === connectionId &&\n op.action === \"__sdk.revoke\" &&\n ![\"succeeded\", \"cancelled\"].includes(op.status),\n );\n },\n async saveOperation(value, expected, lease) {\n const id = key(value.namespace, value.id);\n const current = draft.operations.get(id);\n if (\n current?.version !== expected ||\n (lease &&\n (current.leaseToken !== lease ||\n (current.leaseUntil ?? 0) <= Date.now()))\n )\n return false;\n draft.operations.set(id, value);\n return true;\n },\n async claimOperation(\n namespace,\n id,\n version,\n now,\n leaseToken,\n leaseUntil,\n ) {\n const idKey = key(namespace, id);\n const current = draft.operations.get(idKey);\n if (\n !current ||\n current.version !== version ||\n ![\"pending\", \"outcome_unknown\"].includes(current.status) ||\n current.availableAt > now\n )\n return null;\n const next: Operation = {\n ...current,\n status: \"running\",\n version: current.version + 1,\n attempts: current.attempts + 1,\n leaseToken,\n leaseUntil,\n updatedAt: now,\n };\n draft.operations.set(idKey, next);\n return next;\n },\n async dueOperations(namespace, now, limit) {\n return [...draft.operations.values()]\n .filter(\n (v) =>\n v.namespace === namespace &&\n [\"pending\", \"outcome_unknown\"].includes(v.status) &&\n v.availableAt <= now,\n )\n .slice(0, limit)\n .map((v) => ({ id: v.id, version: v.version }));\n },\n async recoverOperations(namespace, now) {\n let count = 0;\n for (const [id, value] of draft.operations)\n if (\n value.namespace === namespace &&\n value.status === \"running\" &&\n (value.leaseUntil ?? 0) <= now\n ) {\n draft.operations.set(id, {\n ...value,\n status: value.dispatching ? \"outcome_unknown\" : \"pending\",\n version: value.version + 1,\n availableAt: now,\n leaseToken: undefined,\n leaseUntil: undefined,\n });\n count++;\n }\n return count;\n },\n async insertEvent(value) {\n draft.events.set(key(value.namespace, value.id), value);\n },\n async listEvents(scope, after) {\n const values = [...draft.events.values()].filter((v) =>\n matches(v, scope),\n );\n const at = after ? values.findIndex((v) => v.id === after) : -1;\n return values.slice(at + 1);\n },\n async eraseOwner(scope, preserve) {\n for (const [id, value] of draft.flows)\n if (matches(value, scope)) draft.flows.delete(id);\n for (const [id, value] of draft.events)\n if (matches(value, scope)) draft.events.delete(id);\n for (const [id, value] of draft.operations)\n if (\n matches(value, scope) &&\n (!preserve ||\n value.action !== \"__sdk.revoke\" ||\n [\"succeeded\", \"cancelled\"].includes(value.status))\n )\n draft.operations.delete(id);\n for (const [id, value] of draft.connections)\n if (\n matches(value, scope) &&\n (!preserve ||\n ![...draft.operations.values()].some(\n (op) => op.connectionId === value.id && matches(op, scope),\n ))\n )\n draft.connections.delete(id);\n for (const [id, value] of draft.grants)\n if (\n matches(value, scope) &&\n (!preserve ||\n ![...draft.connections.values()].some(\n (c) => c.grantId === value.id && matches(c, scope),\n ))\n )\n draft.grants.delete(id);\n },\n };\n try {\n const result = await work(tx);\n data = draft;\n return result;\n } finally {\n release();\n }\n },\n };\n return store;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
type Json = null | boolean | number | string | Json[] | {
|
|
2
|
+
[key: string]: Json;
|
|
3
|
+
};
|
|
4
|
+
type Purpose = "identity" | "connect";
|
|
5
|
+
type Scope = {
|
|
6
|
+
namespace: string;
|
|
7
|
+
ownerId: string;
|
|
8
|
+
};
|
|
9
|
+
type VerifiedIdentity = {
|
|
10
|
+
provider: string;
|
|
11
|
+
issuer: string;
|
|
12
|
+
subject: string;
|
|
13
|
+
identityNamespace: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
emailVerified: boolean;
|
|
16
|
+
name?: string;
|
|
17
|
+
username?: string;
|
|
18
|
+
};
|
|
19
|
+
type CredentialMaterial = {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken?: string;
|
|
22
|
+
expiresAt?: number;
|
|
23
|
+
scopes?: string[];
|
|
24
|
+
extra?: {
|
|
25
|
+
[key: string]: Json;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
type RemoteAccount = {
|
|
29
|
+
id: string;
|
|
30
|
+
label: string;
|
|
31
|
+
metadata?: {
|
|
32
|
+
[key: string]: Json;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
type Resource = {
|
|
36
|
+
id: string;
|
|
37
|
+
type: string;
|
|
38
|
+
name: string;
|
|
39
|
+
url?: string;
|
|
40
|
+
metadata?: {
|
|
41
|
+
[key: string]: Json;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
type ResourcePage = {
|
|
45
|
+
items: Resource[];
|
|
46
|
+
nextCursor?: string;
|
|
47
|
+
};
|
|
48
|
+
type ProviderContext = {
|
|
49
|
+
credentials: CredentialMaterial;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
fetch: typeof globalThis.fetch;
|
|
52
|
+
};
|
|
53
|
+
type ActionContext = ProviderContext & {
|
|
54
|
+
operationId: string;
|
|
55
|
+
checkpoint: Json;
|
|
56
|
+
saveCheckpoint(value: Json): Promise<void>;
|
|
57
|
+
};
|
|
58
|
+
type ActionDefinition = {
|
|
59
|
+
validate(input: unknown): Json;
|
|
60
|
+
execute(input: Json, context: ActionContext): Promise<Json>;
|
|
61
|
+
reconcile?(input: Json, context: ActionContext): Promise<{
|
|
62
|
+
resolved: true;
|
|
63
|
+
result: Json;
|
|
64
|
+
} | {
|
|
65
|
+
resolved: false;
|
|
66
|
+
}>;
|
|
67
|
+
};
|
|
68
|
+
type AuthorizationInput = {
|
|
69
|
+
state: string;
|
|
70
|
+
verifier: string;
|
|
71
|
+
challenge: string;
|
|
72
|
+
nonce: string;
|
|
73
|
+
purpose: Purpose;
|
|
74
|
+
};
|
|
75
|
+
type AuthorizationResult = {
|
|
76
|
+
identity?: VerifiedIdentity;
|
|
77
|
+
account?: RemoteAccount;
|
|
78
|
+
credentials?: CredentialMaterial;
|
|
79
|
+
};
|
|
80
|
+
interface IntegrationProvider {
|
|
81
|
+
key: string;
|
|
82
|
+
registrationId: string;
|
|
83
|
+
purposes: readonly Purpose[];
|
|
84
|
+
authorization?: {
|
|
85
|
+
url(input: AuthorizationInput): string;
|
|
86
|
+
exchange(input: {
|
|
87
|
+
code: string;
|
|
88
|
+
verifier: string;
|
|
89
|
+
nonce: string;
|
|
90
|
+
purpose: Purpose;
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
}, fetch: typeof globalThis.fetch): Promise<AuthorizationResult>;
|
|
93
|
+
};
|
|
94
|
+
verifyNative?(input: {
|
|
95
|
+
idToken: string;
|
|
96
|
+
nonce: string;
|
|
97
|
+
authorizationCode?: string;
|
|
98
|
+
}, fetch: typeof globalThis.fetch): Promise<VerifiedIdentity>;
|
|
99
|
+
resources?(input: {
|
|
100
|
+
cursor?: string;
|
|
101
|
+
query?: string;
|
|
102
|
+
parentId?: string;
|
|
103
|
+
}, context: ProviderContext): Promise<ResourcePage>;
|
|
104
|
+
refresh?(credentials: CredentialMaterial, context: {
|
|
105
|
+
fetch: typeof globalThis.fetch;
|
|
106
|
+
signal?: AbortSignal;
|
|
107
|
+
}): Promise<CredentialMaterial>;
|
|
108
|
+
revoke?(credentials: CredentialMaterial, context: {
|
|
109
|
+
fetch: typeof globalThis.fetch;
|
|
110
|
+
signal?: AbortSignal;
|
|
111
|
+
}): Promise<void>;
|
|
112
|
+
actions?: Readonly<Record<string, ActionDefinition>>;
|
|
113
|
+
}
|
|
114
|
+
type SealedValue = {
|
|
115
|
+
keyId: string;
|
|
116
|
+
value: string;
|
|
117
|
+
};
|
|
118
|
+
interface TokenVault {
|
|
119
|
+
seal(value: Json, context: string): Promise<SealedValue>;
|
|
120
|
+
open(value: SealedValue, context: string): Promise<Json>;
|
|
121
|
+
}
|
|
122
|
+
type Flow = {
|
|
123
|
+
id: string;
|
|
124
|
+
namespace: string;
|
|
125
|
+
ownerId: string;
|
|
126
|
+
provider: string;
|
|
127
|
+
registrationId: string;
|
|
128
|
+
purpose: Purpose;
|
|
129
|
+
bindingHash: string;
|
|
130
|
+
expiresAt: number;
|
|
131
|
+
secret: SealedValue;
|
|
132
|
+
authorizationEpoch?: number;
|
|
133
|
+
connectionId?: string;
|
|
134
|
+
generation?: number;
|
|
135
|
+
};
|
|
136
|
+
type Grant = {
|
|
137
|
+
id: string;
|
|
138
|
+
namespace: string;
|
|
139
|
+
ownerId: string;
|
|
140
|
+
provider: string;
|
|
141
|
+
registrationId: string;
|
|
142
|
+
account: RemoteAccount;
|
|
143
|
+
version: number;
|
|
144
|
+
status: "active" | "reauth_required" | "revoked";
|
|
145
|
+
credentials: SealedValue;
|
|
146
|
+
expiresAt?: number;
|
|
147
|
+
refreshLease?: string;
|
|
148
|
+
refreshUntil?: number;
|
|
149
|
+
authorizationLease?: string;
|
|
150
|
+
authorizationUntil?: number;
|
|
151
|
+
};
|
|
152
|
+
type Connection = {
|
|
153
|
+
id: string;
|
|
154
|
+
namespace: string;
|
|
155
|
+
ownerId: string;
|
|
156
|
+
provider: string;
|
|
157
|
+
registrationId: string;
|
|
158
|
+
grantId: string;
|
|
159
|
+
account: RemoteAccount;
|
|
160
|
+
generation: number;
|
|
161
|
+
status: "active" | "reauth_required" | "revoked";
|
|
162
|
+
createdAt: number;
|
|
163
|
+
updatedAt: number;
|
|
164
|
+
};
|
|
165
|
+
type OperationStatus = "pending" | "running" | "succeeded" | "failed" | "blocked" | "outcome_unknown" | "cancelled";
|
|
166
|
+
type Operation = {
|
|
167
|
+
id: string;
|
|
168
|
+
namespace: string;
|
|
169
|
+
ownerId: string;
|
|
170
|
+
connectionId: string;
|
|
171
|
+
generation: number;
|
|
172
|
+
action: string;
|
|
173
|
+
idempotencyKey: string;
|
|
174
|
+
fingerprint: string;
|
|
175
|
+
input: SealedValue;
|
|
176
|
+
hostContext?: Json;
|
|
177
|
+
status: OperationStatus;
|
|
178
|
+
version: number;
|
|
179
|
+
attempts: number;
|
|
180
|
+
authRecoveries?: number;
|
|
181
|
+
availableAt: number;
|
|
182
|
+
checkpoint: Json;
|
|
183
|
+
dispatching: boolean;
|
|
184
|
+
leaseToken?: string;
|
|
185
|
+
leaseUntil?: number;
|
|
186
|
+
result?: Json;
|
|
187
|
+
errorCode?: string;
|
|
188
|
+
createdAt: number;
|
|
189
|
+
updatedAt: number;
|
|
190
|
+
};
|
|
191
|
+
type IntegrationEvent = {
|
|
192
|
+
id: string;
|
|
193
|
+
namespace: string;
|
|
194
|
+
ownerId: string;
|
|
195
|
+
operationId: string;
|
|
196
|
+
type: string;
|
|
197
|
+
createdAt: number;
|
|
198
|
+
data: Json;
|
|
199
|
+
};
|
|
200
|
+
interface IntegrationTransaction {
|
|
201
|
+
readonly nativeContext?: unknown;
|
|
202
|
+
lockScope(scope: Scope, allowErased?: boolean): Promise<boolean>;
|
|
203
|
+
authorizationEpoch(scope: Scope, key: string, advance?: boolean): Promise<number>;
|
|
204
|
+
markOwnerErased(scope: Scope): Promise<void>;
|
|
205
|
+
assertAccountOwner(scope: Scope, provider: string, registrationId: string, accountId: string): Promise<void>;
|
|
206
|
+
collectGarbage(namespace: string, now: number, retentionMs: number): Promise<void>;
|
|
207
|
+
insertFlow(flow: Flow): Promise<void>;
|
|
208
|
+
consumeFlow(namespace: string, id: string, bindingHash: string, purpose: Purpose, now: number): Promise<Flow | null>;
|
|
209
|
+
insertGrant(grant: Grant): Promise<void>;
|
|
210
|
+
getGrant(scope: Scope, id: string, lock?: boolean): Promise<Grant | null>;
|
|
211
|
+
saveGrant(grant: Grant, expectedVersion: number): Promise<boolean>;
|
|
212
|
+
insertConnection(connection: Connection): Promise<void>;
|
|
213
|
+
getConnection(scope: Scope, id: string, lock?: boolean): Promise<Connection | null>;
|
|
214
|
+
listConnections(scope: Scope): Promise<Connection[]>;
|
|
215
|
+
saveConnection(connection: Connection, expectedGeneration: number): Promise<boolean>;
|
|
216
|
+
insertOperation(operation: Operation): Promise<Operation>;
|
|
217
|
+
getOperation(scope: Scope, id: string, lock?: boolean): Promise<Operation | null>;
|
|
218
|
+
listOperations(scope: Scope, connectionId?: string): Promise<Operation[]>;
|
|
219
|
+
hasPendingRevocation(scope: Scope, connectionId: string): Promise<boolean>;
|
|
220
|
+
saveOperation(operation: Operation, expectedVersion: number, leaseToken?: string): Promise<boolean>;
|
|
221
|
+
claimOperation(namespace: string, id: string, version: number, now: number, leaseToken: string, leaseUntil: number): Promise<Operation | null>;
|
|
222
|
+
dueOperations(namespace: string, now: number, limit: number): Promise<Array<{
|
|
223
|
+
id: string;
|
|
224
|
+
version: number;
|
|
225
|
+
}>>;
|
|
226
|
+
recoverOperations(namespace: string, now: number): Promise<number>;
|
|
227
|
+
insertEvent(event: IntegrationEvent): Promise<void>;
|
|
228
|
+
listEvents(scope: Scope, after?: string): Promise<IntegrationEvent[]>;
|
|
229
|
+
eraseOwner(scope: Scope, preserveRevocations: boolean): Promise<void>;
|
|
230
|
+
}
|
|
231
|
+
interface IntegrationStore {
|
|
232
|
+
transaction<T>(work: (tx: IntegrationTransaction) => Promise<T>): Promise<T>;
|
|
233
|
+
assertCompatible(): Promise<void>;
|
|
234
|
+
}
|
|
235
|
+
type TaskMessage = {
|
|
236
|
+
taskId: string;
|
|
237
|
+
version: number;
|
|
238
|
+
};
|
|
239
|
+
interface QueueTransport {
|
|
240
|
+
publish(messages: TaskMessage[]): Promise<void>;
|
|
241
|
+
start(handler: (message: TaskMessage) => Promise<void>): Promise<void>;
|
|
242
|
+
stop(): Promise<void>;
|
|
243
|
+
}
|
|
244
|
+
type SdkLogger = {
|
|
245
|
+
info?(fields: Record<string, string | number | boolean>, message: string): void;
|
|
246
|
+
warn?(fields: Record<string, string | number | boolean>, message: string): void;
|
|
247
|
+
error?(fields: Record<string, string | number | boolean>, message: string): void;
|
|
248
|
+
};
|
|
249
|
+
interface ApiRateLimiter {
|
|
250
|
+
take(key: string): Promise<{
|
|
251
|
+
allowed: boolean;
|
|
252
|
+
retryAfterMs: number;
|
|
253
|
+
}>;
|
|
254
|
+
}
|
|
255
|
+
type HostHooks = {
|
|
256
|
+
beforeExecute?(context: unknown, operation: Operation, input: Json): Promise<void>;
|
|
257
|
+
onResult?(context: unknown, operation: Operation, event: IntegrationEvent, input: Json): Promise<void>;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export type { ApiRateLimiter as A, Connection as C, Flow as F, Grant as G, HostHooks as H, IntegrationStore as I, Json as J, Operation as O, Purpose as P, QueueTransport as Q, ResourcePage as R, Scope as S, TokenVault as T, VerifiedIdentity as V, IntegrationTransaction as a, IntegrationEvent as b, TaskMessage as c, IntegrationProvider as d, SdkLogger as e, ActionContext as f, ActionDefinition as g, AuthorizationInput as h, AuthorizationResult as i, CredentialMaterial as j, OperationStatus as k, ProviderContext as l, RemoteAccount as m, Resource as n, SealedValue as o };
|