@portablecore/integrations 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/dist/capabilities.d.ts +65 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +186 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +236 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +46 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +137 -0
- package/dist/provider.js.map +1 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @portablecore/integrations — Surface Capability Resolution
|
|
3
|
+
*
|
|
4
|
+
* The PEP bridge: translates platform integration configuration into
|
|
5
|
+
* `CredentialAvailability[]` that surfaces pass to experts at invocation time.
|
|
6
|
+
*
|
|
7
|
+
* An expert's capabilities are intrinsic — it *knows* how to send SMS,
|
|
8
|
+
* generate presentations, process payments. But whether it *can* do those
|
|
9
|
+
* things on a given surface depends on what integrations that surface has
|
|
10
|
+
* configured. This module answers the question:
|
|
11
|
+
*
|
|
12
|
+
* "What can this surface actually do?"
|
|
13
|
+
*
|
|
14
|
+
* @see {@link https://github.com/portableteam/portablecore/docs/SHARED_INTEGRATIONS_VISION.md}
|
|
15
|
+
*/
|
|
16
|
+
import type { AnySupabaseClient } from "./types.js";
|
|
17
|
+
import type { CapabilityMapping } from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* PEP §4.4 — Credential availability for a capability.
|
|
20
|
+
*
|
|
21
|
+
* This is structurally identical to `CredentialAvailability` from
|
|
22
|
+
* `@portablecore/types`. We define it here to avoid a runtime dependency
|
|
23
|
+
* on the types package (which is devDependencies-only for most consumers).
|
|
24
|
+
*/
|
|
25
|
+
export interface CredentialAvailability {
|
|
26
|
+
/** Capability slug this credential enables */
|
|
27
|
+
capabilitySlug: string;
|
|
28
|
+
/** Credential type (e.g., "oauth:google", "apikey:perplexity") */
|
|
29
|
+
credentialType: string;
|
|
30
|
+
/** Whether credentials are available and valid */
|
|
31
|
+
isAvailable: boolean;
|
|
32
|
+
/** Connection status */
|
|
33
|
+
status?: "connected" | "expired" | "error" | "not_configured";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Discover what integrations are available on this surface.
|
|
37
|
+
*
|
|
38
|
+
* Queries all active platform-level integrations, joins with
|
|
39
|
+
* `integration_providers` for slugs, then maps them to PEP
|
|
40
|
+
* `CredentialAvailability[]` using the capability mapping table.
|
|
41
|
+
*
|
|
42
|
+
* @param supabase - Service-role Supabase client
|
|
43
|
+
* @param platformIdentityId - Optional: scope to a specific platform.
|
|
44
|
+
* If not provided, checks the metaplatform first, then any platform.
|
|
45
|
+
* @param customMappings - Optional: override or extend the default
|
|
46
|
+
* provider-slug → capability mapping
|
|
47
|
+
* @returns Array of credential availability records for PEP invocation
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const capabilities = await getSurfaceCapabilities(supabase)
|
|
52
|
+
* // [
|
|
53
|
+
* // { capabilitySlug: "sms", credentialType: "apikey:twilio", isAvailable: true, status: "connected" },
|
|
54
|
+
* // { capabilitySlug: "email", credentialType: "apikey:postmark", isAvailable: true, status: "connected" },
|
|
55
|
+
* // ]
|
|
56
|
+
*
|
|
57
|
+
* // Pass to PEP invocation:
|
|
58
|
+
* const pepRequest = {
|
|
59
|
+
* credentials: { available: capabilities },
|
|
60
|
+
* // ...
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function getSurfaceCapabilities(supabase: AnySupabaseClient, platformIdentityId?: string, customMappings?: CapabilityMapping[]): Promise<CredentialAvailability[]>;
|
|
65
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAMnD;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,cAAc,EAAE,MAAM,CAAA;IACtB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAA;IACtB,kDAAkD;IAClD,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB;IACxB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,gBAAgB,CAAA;CAC9D;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,iBAAiB,EAC3B,kBAAkB,CAAC,EAAE,MAAM,EAC3B,cAAc,CAAC,EAAE,iBAAiB,EAAE,GACnC,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAkGnC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @portablecore/integrations — Surface Capability Resolution
|
|
4
|
+
*
|
|
5
|
+
* The PEP bridge: translates platform integration configuration into
|
|
6
|
+
* `CredentialAvailability[]` that surfaces pass to experts at invocation time.
|
|
7
|
+
*
|
|
8
|
+
* An expert's capabilities are intrinsic — it *knows* how to send SMS,
|
|
9
|
+
* generate presentations, process payments. But whether it *can* do those
|
|
10
|
+
* things on a given surface depends on what integrations that surface has
|
|
11
|
+
* configured. This module answers the question:
|
|
12
|
+
*
|
|
13
|
+
* "What can this surface actually do?"
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://github.com/portableteam/portablecore/docs/SHARED_INTEGRATIONS_VISION.md}
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.getSurfaceCapabilities = getSurfaceCapabilities;
|
|
19
|
+
const types_js_1 = require("./types.js");
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Surface Capabilities
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Discover what integrations are available on this surface.
|
|
25
|
+
*
|
|
26
|
+
* Queries all active platform-level integrations, joins with
|
|
27
|
+
* `integration_providers` for slugs, then maps them to PEP
|
|
28
|
+
* `CredentialAvailability[]` using the capability mapping table.
|
|
29
|
+
*
|
|
30
|
+
* @param supabase - Service-role Supabase client
|
|
31
|
+
* @param platformIdentityId - Optional: scope to a specific platform.
|
|
32
|
+
* If not provided, checks the metaplatform first, then any platform.
|
|
33
|
+
* @param customMappings - Optional: override or extend the default
|
|
34
|
+
* provider-slug → capability mapping
|
|
35
|
+
* @returns Array of credential availability records for PEP invocation
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const capabilities = await getSurfaceCapabilities(supabase)
|
|
40
|
+
* // [
|
|
41
|
+
* // { capabilitySlug: "sms", credentialType: "apikey:twilio", isAvailable: true, status: "connected" },
|
|
42
|
+
* // { capabilitySlug: "email", credentialType: "apikey:postmark", isAvailable: true, status: "connected" },
|
|
43
|
+
* // ]
|
|
44
|
+
*
|
|
45
|
+
* // Pass to PEP invocation:
|
|
46
|
+
* const pepRequest = {
|
|
47
|
+
* credentials: { available: capabilities },
|
|
48
|
+
* // ...
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
async function getSurfaceCapabilities(supabase, platformIdentityId, customMappings) {
|
|
53
|
+
const mappings = customMappings || types_js_1.DEFAULT_CAPABILITY_MAPPINGS;
|
|
54
|
+
try {
|
|
55
|
+
// Build a set of provider slugs we care about
|
|
56
|
+
const slugsOfInterest = mappings.map((m) => m.providerSlug);
|
|
57
|
+
// Get provider IDs for the slugs we're mapping
|
|
58
|
+
const { data: providers, error: providerError } = await supabase
|
|
59
|
+
.from("integration_providers")
|
|
60
|
+
.select("id, slug")
|
|
61
|
+
.in("slug", slugsOfInterest);
|
|
62
|
+
if (providerError || !providers?.length) {
|
|
63
|
+
return mappings.map((m) => ({
|
|
64
|
+
capabilitySlug: m.capabilitySlug,
|
|
65
|
+
credentialType: m.credentialType,
|
|
66
|
+
isAvailable: false,
|
|
67
|
+
status: "not_configured",
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
// Build a map of provider ID → slug for fast lookup
|
|
71
|
+
const providerIdToSlug = new Map();
|
|
72
|
+
for (const p of providers) {
|
|
73
|
+
providerIdToSlug.set(p.id, p.slug);
|
|
74
|
+
}
|
|
75
|
+
// Query active integrations for these providers
|
|
76
|
+
const providerIds = providers.map((p) => p.id);
|
|
77
|
+
let integrationQuery = supabase
|
|
78
|
+
.from("integrations")
|
|
79
|
+
.select("provider_id, is_active, config, access_token")
|
|
80
|
+
.in("provider_id", providerIds)
|
|
81
|
+
.eq("context_type", "platform")
|
|
82
|
+
.eq("is_active", true);
|
|
83
|
+
// Scope to specific platform if provided
|
|
84
|
+
if (platformIdentityId) {
|
|
85
|
+
integrationQuery = integrationQuery.eq("platform_identity_id", platformIdentityId);
|
|
86
|
+
}
|
|
87
|
+
const { data: integrations, error: intError } = await integrationQuery;
|
|
88
|
+
if (intError) {
|
|
89
|
+
console.warn("[Integrations] Failed to query integrations for capabilities:", intError.message);
|
|
90
|
+
}
|
|
91
|
+
// Build a set of provider slugs that have active integrations
|
|
92
|
+
const activeProviderSlugs = new Set();
|
|
93
|
+
if (integrations) {
|
|
94
|
+
for (const integration of integrations) {
|
|
95
|
+
const slug = providerIdToSlug.get(integration.provider_id);
|
|
96
|
+
if (slug) {
|
|
97
|
+
// Verify the integration has meaningful config or credentials
|
|
98
|
+
const hasToken = !!integration.access_token;
|
|
99
|
+
const hasConfig = integration.config &&
|
|
100
|
+
typeof integration.config === "object" &&
|
|
101
|
+
Object.keys(integration.config).length > 0;
|
|
102
|
+
if (hasToken || hasConfig) {
|
|
103
|
+
activeProviderSlugs.add(slug);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// If no platform-scoped results, try metaplatform fallback
|
|
109
|
+
if (activeProviderSlugs.size === 0 && !platformIdentityId) {
|
|
110
|
+
const metaCapabilities = await tryMetaplatformCapabilities(supabase, providerIds, providerIdToSlug, mappings);
|
|
111
|
+
if (metaCapabilities)
|
|
112
|
+
return metaCapabilities;
|
|
113
|
+
}
|
|
114
|
+
// Map to CredentialAvailability
|
|
115
|
+
return mappings.map((m) => {
|
|
116
|
+
const isActive = activeProviderSlugs.has(m.providerSlug);
|
|
117
|
+
return {
|
|
118
|
+
capabilitySlug: m.capabilitySlug,
|
|
119
|
+
credentialType: m.credentialType,
|
|
120
|
+
isAvailable: isActive,
|
|
121
|
+
status: isActive ? "connected" : "not_configured",
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
console.error("[Integrations] Error resolving surface capabilities:", err);
|
|
127
|
+
return mappings.map((m) => ({
|
|
128
|
+
capabilitySlug: m.capabilitySlug,
|
|
129
|
+
credentialType: m.credentialType,
|
|
130
|
+
isAvailable: false,
|
|
131
|
+
status: "error",
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Metaplatform Fallback
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
async function tryMetaplatformCapabilities(supabase, providerIds, providerIdToSlug, mappings) {
|
|
139
|
+
try {
|
|
140
|
+
const { data: meta } = await supabase
|
|
141
|
+
.from("platform_identity")
|
|
142
|
+
.select("id")
|
|
143
|
+
.eq("is_metaplatform", true)
|
|
144
|
+
.maybeSingle();
|
|
145
|
+
if (!meta?.id)
|
|
146
|
+
return null;
|
|
147
|
+
const { data: integrations } = await supabase
|
|
148
|
+
.from("integrations")
|
|
149
|
+
.select("provider_id, is_active, config, access_token")
|
|
150
|
+
.in("provider_id", providerIds)
|
|
151
|
+
.eq("context_type", "platform")
|
|
152
|
+
.eq("platform_identity_id", meta.id)
|
|
153
|
+
.eq("is_active", true);
|
|
154
|
+
if (!integrations?.length)
|
|
155
|
+
return null;
|
|
156
|
+
const activeSlugs = new Set();
|
|
157
|
+
for (const integration of integrations) {
|
|
158
|
+
const slug = providerIdToSlug.get(integration.provider_id);
|
|
159
|
+
if (slug) {
|
|
160
|
+
const hasToken = !!integration.access_token;
|
|
161
|
+
const hasConfig = integration.config &&
|
|
162
|
+
typeof integration.config === "object" &&
|
|
163
|
+
Object.keys(integration.config).length > 0;
|
|
164
|
+
if (hasToken || hasConfig) {
|
|
165
|
+
activeSlugs.add(slug);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (activeSlugs.size === 0)
|
|
170
|
+
return null;
|
|
171
|
+
return mappings.map((m) => {
|
|
172
|
+
const isActive = activeSlugs.has(m.providerSlug);
|
|
173
|
+
return {
|
|
174
|
+
capabilitySlug: m.capabilitySlug,
|
|
175
|
+
credentialType: m.credentialType,
|
|
176
|
+
isAvailable: isActive,
|
|
177
|
+
status: isActive ? "connected" : "not_configured",
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// platform_identity may not exist — expected on Expert
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @portablecore/integrations — Credential Resolution
|
|
3
|
+
*
|
|
4
|
+
* The core of the package: resolves integration credentials from the
|
|
5
|
+
* `integrations` table with a well-defined fallback chain.
|
|
6
|
+
*
|
|
7
|
+
* Resolution order:
|
|
8
|
+
* 1. Account-level (BYOK) — if scope.accountId provided
|
|
9
|
+
* 2. User-level (OAuth tokens) — if scope.userId provided
|
|
10
|
+
* 3. Platform-specific — if scope.platformIdentityId provided
|
|
11
|
+
* 4. Metaplatform fallback — auto-detected via platform_identity.is_metaplatform
|
|
12
|
+
* 5. Any active platform integration — legacy catch-all
|
|
13
|
+
*
|
|
14
|
+
* This generalizes what Expert's `getProviderApiKey()` does for AI providers
|
|
15
|
+
* and what `getTwilioConfig()` does for Twilio into a single function.
|
|
16
|
+
*/
|
|
17
|
+
import type { AnySupabaseClient, ConfigSource, ProviderConfigResult, ProviderScope } from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Resolve integration credentials for a provider with scope-based fallback.
|
|
20
|
+
*
|
|
21
|
+
* @param supabase - Service-role Supabase client (bypasses RLS)
|
|
22
|
+
* @param providerSlug - Provider slug (e.g. "twilio", "postmark", "openai")
|
|
23
|
+
* @param scope - Optional scope to control the fallback chain
|
|
24
|
+
* @returns The resolved config, or null if no active integration is found
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // Platform-level Twilio config
|
|
29
|
+
* const twilio = await getProviderConfig<TwilioConfig>(supabase, "twilio")
|
|
30
|
+
*
|
|
31
|
+
* // BYOK with account fallback
|
|
32
|
+
* const openai = await getProviderConfig(supabase, "openai", {
|
|
33
|
+
* accountId: "acc_123",
|
|
34
|
+
* })
|
|
35
|
+
* // openai.source === "account" | "platform"
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function getProviderConfig<T = Record<string, unknown>>(supabase: AnySupabaseClient, providerSlug: string, scope?: ProviderScope): Promise<ProviderConfigResult<T> | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Shorthand for getting just the API key string for a provider.
|
|
41
|
+
*
|
|
42
|
+
* Checks `access_token` first, then `config.api_key`, then
|
|
43
|
+
* `credentials.api_key`. Returns null if none found.
|
|
44
|
+
*
|
|
45
|
+
* @param supabase - Service-role Supabase client
|
|
46
|
+
* @param providerSlug - Provider slug
|
|
47
|
+
* @param scope - Optional scope
|
|
48
|
+
* @returns The API key string and its source, or null
|
|
49
|
+
*/
|
|
50
|
+
export declare function getProviderApiKey(supabase: AnySupabaseClient, providerSlug: string, scope?: ProviderScope): Promise<{
|
|
51
|
+
apiKey: string;
|
|
52
|
+
source: ConfigSource;
|
|
53
|
+
providerId: string;
|
|
54
|
+
} | null>;
|
|
55
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACd,MAAM,YAAY,CAAA;AAMnB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,QAAQ,EAAE,iBAAiB,EAC3B,YAAY,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAwBzC;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,iBAAiB,EAC3B,YAAY,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAkC9E"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @portablecore/integrations — Credential Resolution
|
|
4
|
+
*
|
|
5
|
+
* The core of the package: resolves integration credentials from the
|
|
6
|
+
* `integrations` table with a well-defined fallback chain.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order:
|
|
9
|
+
* 1. Account-level (BYOK) — if scope.accountId provided
|
|
10
|
+
* 2. User-level (OAuth tokens) — if scope.userId provided
|
|
11
|
+
* 3. Platform-specific — if scope.platformIdentityId provided
|
|
12
|
+
* 4. Metaplatform fallback — auto-detected via platform_identity.is_metaplatform
|
|
13
|
+
* 5. Any active platform integration — legacy catch-all
|
|
14
|
+
*
|
|
15
|
+
* This generalizes what Expert's `getProviderApiKey()` does for AI providers
|
|
16
|
+
* and what `getTwilioConfig()` does for Twilio into a single function.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.getProviderConfig = getProviderConfig;
|
|
20
|
+
exports.getProviderApiKey = getProviderApiKey;
|
|
21
|
+
const provider_js_1 = require("./provider.js");
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Main Resolver
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/**
|
|
26
|
+
* Resolve integration credentials for a provider with scope-based fallback.
|
|
27
|
+
*
|
|
28
|
+
* @param supabase - Service-role Supabase client (bypasses RLS)
|
|
29
|
+
* @param providerSlug - Provider slug (e.g. "twilio", "postmark", "openai")
|
|
30
|
+
* @param scope - Optional scope to control the fallback chain
|
|
31
|
+
* @returns The resolved config, or null if no active integration is found
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // Platform-level Twilio config
|
|
36
|
+
* const twilio = await getProviderConfig<TwilioConfig>(supabase, "twilio")
|
|
37
|
+
*
|
|
38
|
+
* // BYOK with account fallback
|
|
39
|
+
* const openai = await getProviderConfig(supabase, "openai", {
|
|
40
|
+
* accountId: "acc_123",
|
|
41
|
+
* })
|
|
42
|
+
* // openai.source === "account" | "platform"
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
async function getProviderConfig(supabase, providerSlug, scope) {
|
|
46
|
+
// 1. Resolve provider ID
|
|
47
|
+
const provider = await (0, provider_js_1.getProvider)(supabase, providerSlug);
|
|
48
|
+
if (!provider) {
|
|
49
|
+
console.warn(`[Integrations] Provider not found: "${providerSlug}"`);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
// 2. Walk the fallback chain
|
|
53
|
+
const steps = buildFallbackChain(scope);
|
|
54
|
+
for (const step of steps) {
|
|
55
|
+
const result = await queryIntegration(supabase, provider.id, step);
|
|
56
|
+
if (result) {
|
|
57
|
+
return { ...result, providerId: provider.id };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 3. No integration found at any level
|
|
61
|
+
console.warn(`[Integrations] No active integration for "${providerSlug}"`, scope ? `(scope: ${JSON.stringify(scope)})` : "(no scope)");
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Convenience: Get API Key
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
/**
|
|
68
|
+
* Shorthand for getting just the API key string for a provider.
|
|
69
|
+
*
|
|
70
|
+
* Checks `access_token` first, then `config.api_key`, then
|
|
71
|
+
* `credentials.api_key`. Returns null if none found.
|
|
72
|
+
*
|
|
73
|
+
* @param supabase - Service-role Supabase client
|
|
74
|
+
* @param providerSlug - Provider slug
|
|
75
|
+
* @param scope - Optional scope
|
|
76
|
+
* @returns The API key string and its source, or null
|
|
77
|
+
*/
|
|
78
|
+
async function getProviderApiKey(supabase, providerSlug, scope) {
|
|
79
|
+
const result = await getProviderConfig(supabase, providerSlug, scope);
|
|
80
|
+
if (!result)
|
|
81
|
+
return null;
|
|
82
|
+
// Try access_token first (most common for API keys)
|
|
83
|
+
if (result.accessToken) {
|
|
84
|
+
return {
|
|
85
|
+
apiKey: result.accessToken,
|
|
86
|
+
source: result.source,
|
|
87
|
+
providerId: result.providerId,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Try config.api_key
|
|
91
|
+
const configKey = result.config?.api_key;
|
|
92
|
+
if (typeof configKey === "string" && configKey) {
|
|
93
|
+
return {
|
|
94
|
+
apiKey: configKey,
|
|
95
|
+
source: result.source,
|
|
96
|
+
providerId: result.providerId,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Try credentials.api_key
|
|
100
|
+
const credKey = result.credentials?.api_key;
|
|
101
|
+
if (typeof credKey === "string" && credKey) {
|
|
102
|
+
return {
|
|
103
|
+
apiKey: credKey,
|
|
104
|
+
source: result.source,
|
|
105
|
+
providerId: result.providerId,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build the ordered list of integration lookups to try.
|
|
112
|
+
*/
|
|
113
|
+
function buildFallbackChain(scope) {
|
|
114
|
+
const steps = [];
|
|
115
|
+
// 1. Account-level (BYOK)
|
|
116
|
+
if (scope?.accountId) {
|
|
117
|
+
steps.push({
|
|
118
|
+
source: "account",
|
|
119
|
+
contextType: "account",
|
|
120
|
+
filters: { account_id: scope.accountId },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// 2. User-level (OAuth tokens)
|
|
124
|
+
if (scope?.userId) {
|
|
125
|
+
steps.push({
|
|
126
|
+
source: "user",
|
|
127
|
+
contextType: "user",
|
|
128
|
+
filters: { user_id: scope.userId },
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// 3. Platform-specific
|
|
132
|
+
if (scope?.platformIdentityId) {
|
|
133
|
+
steps.push({
|
|
134
|
+
source: "platform",
|
|
135
|
+
contextType: "platform",
|
|
136
|
+
filters: { platform_identity_id: scope.platformIdentityId },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// 4. Metaplatform fallback (resolved dynamically in queryIntegration)
|
|
140
|
+
steps.push({
|
|
141
|
+
source: "metaplatform",
|
|
142
|
+
contextType: "platform",
|
|
143
|
+
filters: { __metaplatform: "true" }, // sentinel — resolved at query time
|
|
144
|
+
});
|
|
145
|
+
// 5. Any active platform integration (legacy catch-all)
|
|
146
|
+
steps.push({
|
|
147
|
+
source: "platform",
|
|
148
|
+
contextType: "platform",
|
|
149
|
+
filters: {},
|
|
150
|
+
});
|
|
151
|
+
return steps;
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Integration Query
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
/**
|
|
157
|
+
* Query the `integrations` table for a single matching row.
|
|
158
|
+
*/
|
|
159
|
+
async function queryIntegration(supabase, providerId, step) {
|
|
160
|
+
try {
|
|
161
|
+
// Handle metaplatform sentinel
|
|
162
|
+
if (step.filters.__metaplatform) {
|
|
163
|
+
return await queryMetaplatformIntegration(supabase, providerId, step.source);
|
|
164
|
+
}
|
|
165
|
+
let query = supabase
|
|
166
|
+
.from("integrations")
|
|
167
|
+
.select("id, config, credentials, settings, access_token")
|
|
168
|
+
.eq("provider_id", providerId)
|
|
169
|
+
.eq("context_type", step.contextType)
|
|
170
|
+
.eq("is_active", true);
|
|
171
|
+
// Apply scope filters
|
|
172
|
+
for (const [key, value] of Object.entries(step.filters)) {
|
|
173
|
+
if (value !== null && value !== undefined) {
|
|
174
|
+
query = query.eq(key, value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const { data, error } = await query.maybeSingle();
|
|
178
|
+
if (error || !data)
|
|
179
|
+
return null;
|
|
180
|
+
return mapIntegrationRow(data, step.source);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Column might not exist on some platforms — fail silently
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Resolve the metaplatform's integration for a provider.
|
|
189
|
+
*
|
|
190
|
+
* Queries `platform_identity` for the metaplatform row, then looks up
|
|
191
|
+
* the integration scoped to that platform. Fails gracefully if the
|
|
192
|
+
* `platform_identity` table or `is_metaplatform` column doesn't exist
|
|
193
|
+
* (e.g. on Expert, which doesn't have multi-platform support yet).
|
|
194
|
+
*/
|
|
195
|
+
async function queryMetaplatformIntegration(supabase, providerId, source) {
|
|
196
|
+
try {
|
|
197
|
+
// Find the metaplatform
|
|
198
|
+
const { data: meta, error: metaError } = await supabase
|
|
199
|
+
.from("platform_identity")
|
|
200
|
+
.select("id")
|
|
201
|
+
.eq("is_metaplatform", true)
|
|
202
|
+
.maybeSingle();
|
|
203
|
+
if (metaError || !meta?.id)
|
|
204
|
+
return null;
|
|
205
|
+
// Query integration for the metaplatform
|
|
206
|
+
const { data, error } = await supabase
|
|
207
|
+
.from("integrations")
|
|
208
|
+
.select("id, config, credentials, settings, access_token")
|
|
209
|
+
.eq("provider_id", providerId)
|
|
210
|
+
.eq("context_type", "platform")
|
|
211
|
+
.eq("platform_identity_id", meta.id)
|
|
212
|
+
.eq("is_active", true)
|
|
213
|
+
.maybeSingle();
|
|
214
|
+
if (error || !data)
|
|
215
|
+
return null;
|
|
216
|
+
return mapIntegrationRow(data, source);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// platform_identity table may not exist (Expert) — skip silently
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Row Mapping
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
function mapIntegrationRow(row, source) {
|
|
227
|
+
return {
|
|
228
|
+
config: (row.config || {}),
|
|
229
|
+
source,
|
|
230
|
+
integrationId: row.id,
|
|
231
|
+
accessToken: row.access_token,
|
|
232
|
+
credentials: row.credentials,
|
|
233
|
+
settings: row.settings,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @portablecore/integrations
|
|
3
|
+
*
|
|
4
|
+
* Shared integration provider registry and credential resolution for
|
|
5
|
+
* Portable platforms. Extracted from Portable Expert's production
|
|
6
|
+
* integration system.
|
|
7
|
+
*
|
|
8
|
+
* Provides:
|
|
9
|
+
* - Provider lookup by slug (getProvider, getProviders, listProviders)
|
|
10
|
+
* - Credential resolution with scope-based fallback (getProviderConfig)
|
|
11
|
+
* - API key convenience helper (getProviderApiKey)
|
|
12
|
+
* - PEP capability discovery (getSurfaceCapabilities)
|
|
13
|
+
* - Platform-agnostic types
|
|
14
|
+
*
|
|
15
|
+
* All functions accept a Supabase client as a parameter so they work
|
|
16
|
+
* in any Portable platform (Expert, Team, Theater, etc.).
|
|
17
|
+
*
|
|
18
|
+
* "The expert brings expertise. The surface provides integrations."
|
|
19
|
+
*/
|
|
20
|
+
export type { AnySupabaseClient, IntegrationProvider, ProviderScope, ProviderConfigResult, ConfigSource, CapabilityMapping, } from "./types.js";
|
|
21
|
+
export { DEFAULT_CAPABILITY_MAPPINGS } from "./types.js";
|
|
22
|
+
export { getProvider, getProviders, listProviders } from "./provider.js";
|
|
23
|
+
export { getProviderConfig, getProviderApiKey } from "./config.js";
|
|
24
|
+
export { getSurfaceCapabilities } from "./capabilities.js";
|
|
25
|
+
export type { CredentialAvailability } from "./capabilities.js";
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,GAClB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAGxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAGxE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAGlE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @portablecore/integrations
|
|
4
|
+
*
|
|
5
|
+
* Shared integration provider registry and credential resolution for
|
|
6
|
+
* Portable platforms. Extracted from Portable Expert's production
|
|
7
|
+
* integration system.
|
|
8
|
+
*
|
|
9
|
+
* Provides:
|
|
10
|
+
* - Provider lookup by slug (getProvider, getProviders, listProviders)
|
|
11
|
+
* - Credential resolution with scope-based fallback (getProviderConfig)
|
|
12
|
+
* - API key convenience helper (getProviderApiKey)
|
|
13
|
+
* - PEP capability discovery (getSurfaceCapabilities)
|
|
14
|
+
* - Platform-agnostic types
|
|
15
|
+
*
|
|
16
|
+
* All functions accept a Supabase client as a parameter so they work
|
|
17
|
+
* in any Portable platform (Expert, Team, Theater, etc.).
|
|
18
|
+
*
|
|
19
|
+
* "The expert brings expertise. The surface provides integrations."
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.getSurfaceCapabilities = exports.getProviderApiKey = exports.getProviderConfig = exports.listProviders = exports.getProviders = exports.getProvider = exports.DEFAULT_CAPABILITY_MAPPINGS = void 0;
|
|
23
|
+
var types_js_1 = require("./types.js");
|
|
24
|
+
Object.defineProperty(exports, "DEFAULT_CAPABILITY_MAPPINGS", { enumerable: true, get: function () { return types_js_1.DEFAULT_CAPABILITY_MAPPINGS; } });
|
|
25
|
+
// Provider lookup
|
|
26
|
+
var provider_js_1 = require("./provider.js");
|
|
27
|
+
Object.defineProperty(exports, "getProvider", { enumerable: true, get: function () { return provider_js_1.getProvider; } });
|
|
28
|
+
Object.defineProperty(exports, "getProviders", { enumerable: true, get: function () { return provider_js_1.getProviders; } });
|
|
29
|
+
Object.defineProperty(exports, "listProviders", { enumerable: true, get: function () { return provider_js_1.listProviders; } });
|
|
30
|
+
// Credential resolution
|
|
31
|
+
var config_js_1 = require("./config.js");
|
|
32
|
+
Object.defineProperty(exports, "getProviderConfig", { enumerable: true, get: function () { return config_js_1.getProviderConfig; } });
|
|
33
|
+
Object.defineProperty(exports, "getProviderApiKey", { enumerable: true, get: function () { return config_js_1.getProviderApiKey; } });
|
|
34
|
+
// PEP capability discovery
|
|
35
|
+
var capabilities_js_1 = require("./capabilities.js");
|
|
36
|
+
Object.defineProperty(exports, "getSurfaceCapabilities", { enumerable: true, get: function () { return capabilities_js_1.getSurfaceCapabilities; } });
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAYH,uCAAwD;AAA/C,uHAAA,2BAA2B,OAAA;AAEpC,kBAAkB;AAClB,6CAAwE;AAA/D,0GAAA,WAAW,OAAA;AAAE,2GAAA,YAAY,OAAA;AAAE,4GAAA,aAAa,OAAA;AAEjD,wBAAwB;AACxB,yCAAkE;AAAzD,8GAAA,iBAAiB,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAE7C,2BAA2B;AAC3B,qDAA0D;AAAjD,yHAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @portablecore/integrations — Provider Lookup
|
|
3
|
+
*
|
|
4
|
+
* Canonical functions for querying the `integration_providers` table.
|
|
5
|
+
* Every other module in this package (and every consumer) should use
|
|
6
|
+
* these functions instead of querying `integration_providers` directly.
|
|
7
|
+
*
|
|
8
|
+
* The `slug` column is the canonical identifier across all platforms.
|
|
9
|
+
*/
|
|
10
|
+
import type { AnySupabaseClient, IntegrationProvider } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Look up an integration provider by its canonical slug.
|
|
13
|
+
*
|
|
14
|
+
* @param supabase - Any Supabase client (service-role recommended for server use)
|
|
15
|
+
* @param slug - Provider slug (e.g. "twilio", "postmark", "openai")
|
|
16
|
+
* @returns The provider record, or null if not found / inactive
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const twilio = await getProvider(supabase, "twilio")
|
|
21
|
+
* if (!twilio) throw new Error("Twilio not configured")
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function getProvider(supabase: AnySupabaseClient, slug: string): Promise<IntegrationProvider | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Look up multiple integration providers by slug.
|
|
27
|
+
*
|
|
28
|
+
* @param supabase - Any Supabase client
|
|
29
|
+
* @param slugs - Array of provider slugs
|
|
30
|
+
* @returns Map of slug → IntegrationProvider (missing slugs are omitted)
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const providers = await getProviders(supabase, ["twilio", "postmark"])
|
|
35
|
+
* const twilio = providers.get("twilio")
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function getProviders(supabase: AnySupabaseClient, slugs: string[]): Promise<Map<string, IntegrationProvider>>;
|
|
39
|
+
/**
|
|
40
|
+
* List all active integration providers.
|
|
41
|
+
*
|
|
42
|
+
* @param supabase - Any Supabase client
|
|
43
|
+
* @returns Array of all active providers, sorted by display_order
|
|
44
|
+
*/
|
|
45
|
+
export declare function listProviders(supabase: AnySupabaseClient): Promise<IntegrationProvider[]>;
|
|
46
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAMxE;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAqBrC;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAyB3C;AAMD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAkBhC"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @portablecore/integrations — Provider Lookup
|
|
4
|
+
*
|
|
5
|
+
* Canonical functions for querying the `integration_providers` table.
|
|
6
|
+
* Every other module in this package (and every consumer) should use
|
|
7
|
+
* these functions instead of querying `integration_providers` directly.
|
|
8
|
+
*
|
|
9
|
+
* The `slug` column is the canonical identifier across all platforms.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getProvider = getProvider;
|
|
13
|
+
exports.getProviders = getProviders;
|
|
14
|
+
exports.listProviders = listProviders;
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Single Provider Lookup
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Look up an integration provider by its canonical slug.
|
|
20
|
+
*
|
|
21
|
+
* @param supabase - Any Supabase client (service-role recommended for server use)
|
|
22
|
+
* @param slug - Provider slug (e.g. "twilio", "postmark", "openai")
|
|
23
|
+
* @returns The provider record, or null if not found / inactive
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const twilio = await getProvider(supabase, "twilio")
|
|
28
|
+
* if (!twilio) throw new Error("Twilio not configured")
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
async function getProvider(supabase, slug) {
|
|
32
|
+
try {
|
|
33
|
+
const { data, error } = await supabase
|
|
34
|
+
.from("integration_providers")
|
|
35
|
+
.select("id, slug, name, display_name, category, is_active, config_fields, auth_scopes")
|
|
36
|
+
.eq("slug", slug)
|
|
37
|
+
.single();
|
|
38
|
+
if (error || !data) {
|
|
39
|
+
if (error?.code !== "PGRST116") {
|
|
40
|
+
// PGRST116 = "no rows returned" — expected when provider doesn't exist
|
|
41
|
+
console.warn(`[Integrations] Provider lookup failed for "${slug}":`, error?.message);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return mapProviderRow(data);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.error(`[Integrations] Unexpected error looking up provider "${slug}":`, err);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Multiple Provider Lookup
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Look up multiple integration providers by slug.
|
|
57
|
+
*
|
|
58
|
+
* @param supabase - Any Supabase client
|
|
59
|
+
* @param slugs - Array of provider slugs
|
|
60
|
+
* @returns Map of slug → IntegrationProvider (missing slugs are omitted)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const providers = await getProviders(supabase, ["twilio", "postmark"])
|
|
65
|
+
* const twilio = providers.get("twilio")
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
async function getProviders(supabase, slugs) {
|
|
69
|
+
const result = new Map();
|
|
70
|
+
if (slugs.length === 0)
|
|
71
|
+
return result;
|
|
72
|
+
try {
|
|
73
|
+
const { data, error } = await supabase
|
|
74
|
+
.from("integration_providers")
|
|
75
|
+
.select("id, slug, name, display_name, category, is_active, config_fields, auth_scopes")
|
|
76
|
+
.in("slug", slugs);
|
|
77
|
+
if (error || !data) {
|
|
78
|
+
console.warn("[Integrations] Batch provider lookup failed:", error?.message);
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
for (const row of data) {
|
|
82
|
+
const provider = mapProviderRow(row);
|
|
83
|
+
result.set(provider.slug, provider);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error("[Integrations] Unexpected error in batch provider lookup:", err);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// All Active Providers
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* List all active integration providers.
|
|
96
|
+
*
|
|
97
|
+
* @param supabase - Any Supabase client
|
|
98
|
+
* @returns Array of all active providers, sorted by display_order
|
|
99
|
+
*/
|
|
100
|
+
async function listProviders(supabase) {
|
|
101
|
+
try {
|
|
102
|
+
const { data, error } = await supabase
|
|
103
|
+
.from("integration_providers")
|
|
104
|
+
.select("id, slug, name, display_name, category, is_active, config_fields, auth_scopes")
|
|
105
|
+
.eq("is_active", true)
|
|
106
|
+
.order("display_order", { ascending: true });
|
|
107
|
+
if (error || !data) {
|
|
108
|
+
console.warn("[Integrations] Failed to list providers:", error?.message);
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
return data.map(mapProviderRow);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error("[Integrations] Unexpected error listing providers:", err);
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Row Mapping
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Map a raw database row to the typed IntegrationProvider interface.
|
|
123
|
+
* Handles column name differences (snake_case → camelCase).
|
|
124
|
+
*/
|
|
125
|
+
function mapProviderRow(row) {
|
|
126
|
+
return {
|
|
127
|
+
id: row.id,
|
|
128
|
+
slug: row.slug,
|
|
129
|
+
name: row.name,
|
|
130
|
+
displayName: row.display_name || row.name,
|
|
131
|
+
category: row.category,
|
|
132
|
+
isActive: row.is_active !== false,
|
|
133
|
+
configFields: row.config_fields,
|
|
134
|
+
authScopes: row.auth_scopes,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @portablecore/integrations — Type definitions
|
|
3
|
+
*
|
|
4
|
+
* Core types for integration provider lookup and credential resolution.
|
|
5
|
+
* These mirror the shared `integration_providers` and `integrations` tables
|
|
6
|
+
* that exist on every Portable platform (Expert, Team, Theater, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export type AnySupabaseClient = any;
|
|
9
|
+
/**
|
|
10
|
+
* A registered integration provider (Twilio, Postmark, OpenAI, etc.).
|
|
11
|
+
*
|
|
12
|
+
* Queried from the `integration_providers` table using `slug` as the
|
|
13
|
+
* canonical identifier.
|
|
14
|
+
*/
|
|
15
|
+
export interface IntegrationProvider {
|
|
16
|
+
id: string;
|
|
17
|
+
slug: string;
|
|
18
|
+
name: string;
|
|
19
|
+
displayName: string;
|
|
20
|
+
category?: string;
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
configFields?: unknown[];
|
|
23
|
+
authScopes?: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Scope for credential resolution.
|
|
27
|
+
*
|
|
28
|
+
* Determines which `integrations` rows are checked and in what order:
|
|
29
|
+
* 1. Account-level (BYOK) — if `accountId` provided
|
|
30
|
+
* 2. User-level (OAuth tokens) — if `userId` provided
|
|
31
|
+
* 3. Platform-specific — if `platformIdentityId` provided
|
|
32
|
+
* 4. Metaplatform fallback — auto-detected via `is_metaplatform`
|
|
33
|
+
* 5. Any active platform integration — legacy catch-all
|
|
34
|
+
*/
|
|
35
|
+
export interface ProviderScope {
|
|
36
|
+
/** Check account-level integration first (BYOK API keys) */
|
|
37
|
+
accountId?: string;
|
|
38
|
+
/** Check user-level integration (OAuth tokens) */
|
|
39
|
+
userId?: string;
|
|
40
|
+
/** Check a specific platform's integration */
|
|
41
|
+
platformIdentityId?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The resolved configuration for an integration provider.
|
|
45
|
+
*
|
|
46
|
+
* Generic parameter `T` allows callers to type the config object:
|
|
47
|
+
* ```ts
|
|
48
|
+
* const result = await getProviderConfig<TwilioConfig>(supabase, "twilio")
|
|
49
|
+
* result?.config.accountSid // typed
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export interface ProviderConfigResult<T = Record<string, unknown>> {
|
|
53
|
+
/** The integration's JSONB config, typed by the caller */
|
|
54
|
+
config: T;
|
|
55
|
+
/** Where the credential was resolved from */
|
|
56
|
+
source: ConfigSource;
|
|
57
|
+
/** The integration_providers.id */
|
|
58
|
+
providerId: string;
|
|
59
|
+
/** The integrations.id */
|
|
60
|
+
integrationId: string;
|
|
61
|
+
/** The access_token column (API keys, OAuth tokens) */
|
|
62
|
+
accessToken?: string;
|
|
63
|
+
/** The credentials JSONB column (structured secrets) */
|
|
64
|
+
credentials?: Record<string, unknown>;
|
|
65
|
+
/** The settings JSONB column (non-secret configuration) */
|
|
66
|
+
settings?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
export type ConfigSource = "account" | "user" | "platform" | "metaplatform";
|
|
69
|
+
/**
|
|
70
|
+
* Maps an integration provider category to a PEP credential type.
|
|
71
|
+
*
|
|
72
|
+
* Used by `getSurfaceCapabilities()` to translate database rows into
|
|
73
|
+
* the `CredentialAvailability` type that PEP invocations consume.
|
|
74
|
+
*/
|
|
75
|
+
export interface CapabilityMapping {
|
|
76
|
+
/** The integration_providers slug (e.g. "twilio") */
|
|
77
|
+
providerSlug: string;
|
|
78
|
+
/** The PEP capability slug (e.g. "sms") */
|
|
79
|
+
capabilitySlug: string;
|
|
80
|
+
/** The PEP credential type (e.g. "apikey:twilio") */
|
|
81
|
+
credentialType: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Default mappings from provider slugs to PEP capabilities.
|
|
85
|
+
*
|
|
86
|
+
* Surfaces use these to tell experts what actions are available.
|
|
87
|
+
* This list grows as new integrations are added to the platform.
|
|
88
|
+
*/
|
|
89
|
+
export declare const DEFAULT_CAPABILITY_MAPPINGS: CapabilityMapping[];
|
|
90
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAA;AAMnC;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AAMD;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,0DAA0D;IAC1D,MAAM,EAAE,CAAC,CAAA;IACT,6CAA6C;IAC7C,MAAM,EAAE,YAAY,CAAA;IACpB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,cAAc,CAAA;AAM3E;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,EAAE,iBAAiB,EAS1D,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @portablecore/integrations — Type definitions
|
|
4
|
+
*
|
|
5
|
+
* Core types for integration provider lookup and credential resolution.
|
|
6
|
+
* These mirror the shared `integration_providers` and `integrations` tables
|
|
7
|
+
* that exist on every Portable platform (Expert, Team, Theater, etc.).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DEFAULT_CAPABILITY_MAPPINGS = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* Default mappings from provider slugs to PEP capabilities.
|
|
13
|
+
*
|
|
14
|
+
* Surfaces use these to tell experts what actions are available.
|
|
15
|
+
* This list grows as new integrations are added to the platform.
|
|
16
|
+
*/
|
|
17
|
+
exports.DEFAULT_CAPABILITY_MAPPINGS = [
|
|
18
|
+
{ providerSlug: "twilio", capabilitySlug: "sms", credentialType: "apikey:twilio" },
|
|
19
|
+
{ providerSlug: "postmark", capabilitySlug: "email", credentialType: "apikey:postmark" },
|
|
20
|
+
{ providerSlug: "stripe", capabilitySlug: "payments", credentialType: "apikey:stripe" },
|
|
21
|
+
{ providerSlug: "gamma", capabilitySlug: "presentations", credentialType: "oauth:gamma" },
|
|
22
|
+
{ providerSlug: "google-classroom", capabilitySlug: "classroom", credentialType: "oauth:google-classroom" },
|
|
23
|
+
{ providerSlug: "google-calendar", capabilitySlug: "calendar", credentialType: "oauth:google-calendar" },
|
|
24
|
+
{ providerSlug: "lucidlink", capabilitySlug: "storage", credentialType: "apikey:lucidlink" },
|
|
25
|
+
{ providerSlug: "wistia", capabilitySlug: "video", credentialType: "apikey:wistia" },
|
|
26
|
+
];
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAoGH;;;;;GAKG;AACU,QAAA,2BAA2B,GAAwB;IAC9D,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE;IAClF,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE;IACxF,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE;IACvF,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE;IACzF,EAAE,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,wBAAwB,EAAE;IAC3G,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,uBAAuB,EAAE;IACxG,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,kBAAkB,EAAE;IAC5F,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE;CACrF,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@portablecore/integrations",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared integration provider registry and credential resolution for Portable platforms",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./provider": {
|
|
13
|
+
"types": "./dist/provider.d.ts",
|
|
14
|
+
"default": "./dist/provider.js"
|
|
15
|
+
},
|
|
16
|
+
"./config": {
|
|
17
|
+
"types": "./dist/config.d.ts",
|
|
18
|
+
"default": "./dist/config.js"
|
|
19
|
+
},
|
|
20
|
+
"./capabilities": {
|
|
21
|
+
"types": "./dist/capabilities.d.ts",
|
|
22
|
+
"default": "./dist/capabilities.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"dev": "tsc --watch",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"portable",
|
|
36
|
+
"integrations",
|
|
37
|
+
"provider",
|
|
38
|
+
"credentials",
|
|
39
|
+
"pep"
|
|
40
|
+
],
|
|
41
|
+
"author": "Portable",
|
|
42
|
+
"license": "UNLICENSED",
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@supabase/supabase-js": "^2.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@supabase/supabase-js": "^2.49.0",
|
|
48
|
+
"typescript": "^5.3.0"
|
|
49
|
+
}
|
|
50
|
+
}
|