@tangle-network/agent-runtime 0.50.0 → 0.51.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/agent.js +1 -1
- package/dist/{chunk-RHW75JW5.js → chunk-47SWANFA.js} +2 -2
- package/dist/{chunk-ML4IXGTV.js → chunk-FKHNHUXP.js} +2 -2
- package/dist/{chunk-CM2IK7VS.js → chunk-FQH33M5N.js} +13 -4
- package/dist/chunk-FQH33M5N.js.map +1 -0
- package/dist/chunk-G3RGMA7C.js +361 -0
- package/dist/chunk-G3RGMA7C.js.map +1 -0
- package/dist/{chunk-NDM5VXZW.js → chunk-HAA4KZUD.js} +7 -5
- package/dist/{chunk-NDM5VXZW.js.map → chunk-HAA4KZUD.js.map} +1 -1
- package/dist/{chunk-OM3YNZIW.js → chunk-HYG4ISNS.js} +5 -360
- package/dist/chunk-HYG4ISNS.js.map +1 -0
- package/dist/{chunk-BKAIVNFA.js → chunk-XEI7AIHU.js} +3 -3
- package/dist/improvement.d.ts +96 -8
- package/dist/improvement.js +191 -9
- package/dist/improvement.js.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +423 -0
- package/dist/intelligence.js +427 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/loop-runner-bin.js +4 -3
- package/dist/loops.js +1 -1
- package/dist/mcp/bin.js +5 -4
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.js +6 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/platform.d.ts +120 -62
- package/dist/platform.js +68 -26
- package/dist/platform.js.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/workflow.js +1 -1
- package/package.json +6 -1
- package/dist/chunk-CM2IK7VS.js.map +0 -1
- package/dist/chunk-OM3YNZIW.js.map +0 -1
- /package/dist/{chunk-RHW75JW5.js.map → chunk-47SWANFA.js.map} +0 -0
- /package/dist/{chunk-ML4IXGTV.js.map → chunk-FKHNHUXP.js.map} +0 -0
- /package/dist/{chunk-BKAIVNFA.js.map → chunk-XEI7AIHU.js.map} +0 -0
package/dist/platform.d.ts
CHANGED
|
@@ -68,15 +68,17 @@ declare class PlatformAuthClient {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* Server-side client for the Tangle platform's
|
|
72
|
-
* (`/v1/
|
|
73
|
-
*
|
|
71
|
+
* Server-side client for the Tangle platform's integration hub
|
|
72
|
+
* (`/v1/hub/*`). Consumer apps use this instead of rolling their own
|
|
73
|
+
* OAuth + connection tables.
|
|
74
74
|
*
|
|
75
75
|
* Auth: the caller supplies a bearer (either the user's API key from
|
|
76
76
|
* cross-site exchange, or a platform service token) on construction.
|
|
77
|
-
* Per-request override via `headers` is supported.
|
|
78
77
|
*
|
|
79
|
-
* Endpoint contract: `
|
|
78
|
+
* Endpoint contract (authoritative): the platform's `src/lib/hub-contract.ts`
|
|
79
|
+
* + `src/routes/hub.ts`. The platform wraps every response in
|
|
80
|
+
* `{ success, data }`; non-2xx or `success:false` surfaces as `PlatformHubError`
|
|
81
|
+
* carrying the real upstream status.
|
|
80
82
|
*/
|
|
81
83
|
interface PlatformHubClientOptions {
|
|
82
84
|
/** Platform base URL, e.g. `https://id.tangle.tools`. */
|
|
@@ -86,72 +88,112 @@ interface PlatformHubClientOptions {
|
|
|
86
88
|
/** Override fetch (tests + edge runtimes). */
|
|
87
89
|
fetchImpl?: typeof fetch;
|
|
88
90
|
}
|
|
91
|
+
/** A live integration connection, as returned by `/v1/hub/connections`. */
|
|
89
92
|
interface PlatformConnection {
|
|
90
93
|
id: string;
|
|
91
94
|
providerId: string;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
updatedAt?: string;
|
|
103
|
-
}
|
|
95
|
+
displayName: string;
|
|
96
|
+
accountDisplay: string | null;
|
|
97
|
+
scopes: string[];
|
|
98
|
+
status: 'active' | 'revoked' | 'unhealthy' | 'reconnect_required' | (string & {});
|
|
99
|
+
health: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {});
|
|
100
|
+
createdAt: string;
|
|
101
|
+
updatedAt: string;
|
|
102
|
+
lastUsedAt: string | null;
|
|
103
|
+
}
|
|
104
|
+
/** A connectable provider in the catalog (`/v1/hub/providers`). */
|
|
104
105
|
interface PlatformCatalogProvider {
|
|
105
106
|
providerId: string;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
title?: string;
|
|
108
|
+
authKind?: string;
|
|
109
|
+
category?: string;
|
|
110
|
+
scopes?: string[];
|
|
111
|
+
capabilityCount?: number;
|
|
112
|
+
native?: boolean;
|
|
113
|
+
/** Whether the OAuth app's credentials are wired — the UI offers Connect
|
|
114
|
+
* only when true. */
|
|
115
|
+
configured?: boolean;
|
|
110
116
|
[k: string]: unknown;
|
|
111
117
|
}
|
|
112
|
-
interface
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
scopes?: string[];
|
|
118
|
+
interface CatalogResult {
|
|
119
|
+
providers: PlatformCatalogProvider[];
|
|
120
|
+
/** Count of substrate-bundled connectors behind the catalog. */
|
|
121
|
+
substrateBundled?: number;
|
|
117
122
|
[k: string]: unknown;
|
|
118
123
|
}
|
|
119
124
|
interface StartAuthInput {
|
|
125
|
+
/** The provider to connect (goes in the URL path). */
|
|
120
126
|
providerId: string;
|
|
121
|
-
|
|
127
|
+
/** Accepted for interface compatibility; the platform's start endpoint is
|
|
128
|
+
* provider-level and does not consume a connector id. */
|
|
129
|
+
connectorId?: string;
|
|
122
130
|
/** Where the platform redirects the user back to after OAuth. */
|
|
123
131
|
returnUrl: string;
|
|
132
|
+
/** Accepted for interface compatibility; not consumed by the start endpoint. */
|
|
124
133
|
requestedScopes?: string[];
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
/** Required when the bearer is a service token impersonating a user. */
|
|
128
|
-
ownerUserId?: string;
|
|
134
|
+
/** CLI flow flag — affects the platform's post-auth redirect handling. */
|
|
135
|
+
cli?: boolean;
|
|
129
136
|
}
|
|
130
137
|
interface StartAuthResult {
|
|
138
|
+
/** The URL to send the user to. Normalized across the platform's two start
|
|
139
|
+
* branches: github returns `authorizationUrl`, substrate returns
|
|
140
|
+
* `redirectUrl`. */
|
|
131
141
|
authorizationUrl: string;
|
|
132
142
|
state: string;
|
|
143
|
+
expiresAt?: string;
|
|
144
|
+
scopes?: string[];
|
|
133
145
|
}
|
|
134
|
-
interface
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
interface ConnectionHealth {
|
|
147
|
+
status: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {});
|
|
148
|
+
checkedAt: string;
|
|
149
|
+
error?: {
|
|
150
|
+
code: string;
|
|
151
|
+
message: string;
|
|
140
152
|
};
|
|
141
|
-
ttlMs: number;
|
|
142
153
|
}
|
|
143
|
-
interface
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
interface ConnectionHealthResult {
|
|
155
|
+
connection: PlatformConnection;
|
|
156
|
+
health: ConnectionHealth;
|
|
146
157
|
}
|
|
158
|
+
/** Last-known health for a connection, derived from the connection row. */
|
|
147
159
|
interface HealthCheck {
|
|
148
160
|
connectionId: string;
|
|
149
161
|
providerId: string;
|
|
150
|
-
|
|
151
|
-
status: '
|
|
152
|
-
checks?: Record<string, unknown>;
|
|
162
|
+
/** Mirrors `PlatformConnection.health`. */
|
|
163
|
+
status: ConnectionHealth['status'];
|
|
153
164
|
checkedAt?: string;
|
|
154
165
|
}
|
|
166
|
+
interface MintTokenInput {
|
|
167
|
+
/** The hub action the token authorizes (e.g. `slack.chat.postMessage`). */
|
|
168
|
+
actionPath: string;
|
|
169
|
+
/** Bind to a specific connection, or … */
|
|
170
|
+
connectionId?: string;
|
|
171
|
+
/** … resolve the connection by provider for the calling user. */
|
|
172
|
+
provider?: string;
|
|
173
|
+
}
|
|
174
|
+
interface MintTokenResult {
|
|
175
|
+
tokenId: string;
|
|
176
|
+
token: string;
|
|
177
|
+
expiresAt: string;
|
|
178
|
+
}
|
|
179
|
+
interface ExecInput {
|
|
180
|
+
/** The hub action path to execute. */
|
|
181
|
+
path: string;
|
|
182
|
+
input?: unknown;
|
|
183
|
+
connectionId?: string;
|
|
184
|
+
}
|
|
185
|
+
interface PlatformHubStatus {
|
|
186
|
+
contract?: unknown;
|
|
187
|
+
principal: {
|
|
188
|
+
kind: string;
|
|
189
|
+
userId: string;
|
|
190
|
+
[k: string]: unknown;
|
|
191
|
+
};
|
|
192
|
+
connections: {
|
|
193
|
+
connectedProviderCount: number;
|
|
194
|
+
unhealthyProviderCount: number;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
155
197
|
declare class PlatformHubError extends Error {
|
|
156
198
|
readonly status: number;
|
|
157
199
|
readonly code: string | undefined;
|
|
@@ -163,35 +205,51 @@ declare class PlatformHubClient {
|
|
|
163
205
|
private readonly bearer;
|
|
164
206
|
private readonly fetchImpl;
|
|
165
207
|
constructor(options: PlatformHubClientOptions);
|
|
166
|
-
/**
|
|
167
|
-
catalog(): Promise<
|
|
168
|
-
|
|
169
|
-
} & Record<string, unknown>>;
|
|
170
|
-
/** List the calling user's integration connections. */
|
|
208
|
+
/** GET /v1/hub/providers — the connectable provider catalog. */
|
|
209
|
+
catalog(): Promise<CatalogResult>;
|
|
210
|
+
/** GET /v1/hub/connections — the calling user's live connections. */
|
|
171
211
|
listConnections(): Promise<PlatformConnection[]>;
|
|
172
|
-
/**
|
|
212
|
+
/** DELETE /v1/hub/connections/:connectionId — revoke + disable a connection. */
|
|
173
213
|
revokeConnection(connectionId: string): Promise<{
|
|
174
214
|
connection: PlatformConnection;
|
|
175
|
-
revokedGrants: unknown[];
|
|
176
|
-
providerRevocation: {
|
|
177
|
-
ok: boolean;
|
|
178
|
-
};
|
|
179
215
|
}>;
|
|
180
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* POST /v1/hub/connections/:provider/start — begin OAuth/grant. The provider
|
|
218
|
+
* is taken from the URL; the body carries `returnUrl` (+ `cli`). The platform's
|
|
219
|
+
* two start branches name the URL field differently (github → `authorizationUrl`,
|
|
220
|
+
* substrate → `redirectUrl`); this normalizes to `authorizationUrl`.
|
|
221
|
+
*/
|
|
181
222
|
startAuth(input: StartAuthInput): Promise<StartAuthResult>;
|
|
182
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Last-known health for every connection. The platform has no global
|
|
225
|
+
* healthcheck listing — health rides on each connection row — so this derives
|
|
226
|
+
* the list from `listConnections()` (one request, no extra round-trips).
|
|
227
|
+
*/
|
|
183
228
|
listHealthchecks(): Promise<HealthCheck[]>;
|
|
184
|
-
/**
|
|
229
|
+
/**
|
|
230
|
+
* POST /v1/hub/connections/:connectionId/health — trigger a fresh health
|
|
231
|
+
* probe for one connection and return its updated state.
|
|
232
|
+
*/
|
|
233
|
+
checkConnectionHealth(connectionId: string): Promise<ConnectionHealthResult>;
|
|
234
|
+
/**
|
|
235
|
+
* Trigger a fresh health probe across all of the user's connections. The
|
|
236
|
+
* platform exposes health per-connection only, so this fans out over
|
|
237
|
+
* `listConnections()`. `scheduled` is the number of probes dispatched.
|
|
238
|
+
*/
|
|
185
239
|
runHealthchecks(): Promise<{
|
|
186
240
|
scheduled: number;
|
|
187
241
|
}>;
|
|
242
|
+
/** GET /v1/hub/status — principal + aggregate connection counts. */
|
|
243
|
+
status(): Promise<PlatformHubStatus>;
|
|
188
244
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
245
|
+
* POST /v1/hub/tokens — mint a short-lived, action-scoped capability token a
|
|
246
|
+
* sandbox can use to invoke one hub action on the user's behalf without
|
|
247
|
+
* seeing the underlying provider credential.
|
|
192
248
|
*/
|
|
193
|
-
|
|
249
|
+
mintToken(input: MintTokenInput): Promise<MintTokenResult>;
|
|
250
|
+
/** POST /v1/hub/exec — execute a hub action and return its result. */
|
|
251
|
+
exec(input: ExecInput): Promise<unknown>;
|
|
194
252
|
private request;
|
|
195
253
|
}
|
|
196
254
|
|
|
197
|
-
export { type AuthorizeUrlOptions, type
|
|
255
|
+
export { type AuthorizeUrlOptions, type CatalogResult, type ConnectionHealth, type ConnectionHealthResult, type ExchangeCodeResult, type ExecInput, type HealthCheck, type MintTokenInput, type MintTokenResult, PlatformAuthClient, type PlatformAuthClientOptions, PlatformAuthError, type PlatformCatalogProvider, type PlatformConnection, PlatformHubClient, type PlatformHubClientOptions, PlatformHubError, type PlatformHubStatus, type StartAuthInput, type StartAuthResult };
|
package/dist/platform.js
CHANGED
|
@@ -92,48 +92,90 @@ var PlatformHubClient = class {
|
|
|
92
92
|
this.bearer = options.bearer;
|
|
93
93
|
this.fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
94
94
|
}
|
|
95
|
-
/**
|
|
95
|
+
/** GET /v1/hub/providers — the connectable provider catalog. */
|
|
96
96
|
catalog() {
|
|
97
|
-
return this.request("GET", "/v1/
|
|
97
|
+
return this.request("GET", "/v1/hub/providers");
|
|
98
98
|
}
|
|
99
|
-
/**
|
|
99
|
+
/** GET /v1/hub/connections — the calling user's live connections. */
|
|
100
100
|
async listConnections() {
|
|
101
101
|
const data = await this.request(
|
|
102
102
|
"GET",
|
|
103
|
-
"/v1/
|
|
103
|
+
"/v1/hub/connections"
|
|
104
104
|
);
|
|
105
105
|
return data.connections;
|
|
106
106
|
}
|
|
107
|
-
/**
|
|
107
|
+
/** DELETE /v1/hub/connections/:connectionId — revoke + disable a connection. */
|
|
108
108
|
revokeConnection(connectionId) {
|
|
109
|
-
return this.request(
|
|
110
|
-
"DELETE",
|
|
111
|
-
`/v1/integrations/connections/${encodeURIComponent(connectionId)}`
|
|
112
|
-
);
|
|
109
|
+
return this.request("DELETE", `/v1/hub/connections/${encodeURIComponent(connectionId)}`);
|
|
113
110
|
}
|
|
114
|
-
/**
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
/**
|
|
112
|
+
* POST /v1/hub/connections/:provider/start — begin OAuth/grant. The provider
|
|
113
|
+
* is taken from the URL; the body carries `returnUrl` (+ `cli`). The platform's
|
|
114
|
+
* two start branches name the URL field differently (github → `authorizationUrl`,
|
|
115
|
+
* substrate → `redirectUrl`); this normalizes to `authorizationUrl`.
|
|
116
|
+
*/
|
|
117
|
+
async startAuth(input) {
|
|
118
|
+
const body = { returnUrl: input.returnUrl };
|
|
119
|
+
if (input.cli !== void 0) body.cli = input.cli;
|
|
120
|
+
const data = await this.request("POST", `/v1/hub/connections/${encodeURIComponent(input.providerId)}/start`, body);
|
|
121
|
+
const authorizationUrl = data.authorizationUrl ?? data.redirectUrl;
|
|
122
|
+
if (!authorizationUrl) {
|
|
123
|
+
throw new PlatformHubError(
|
|
124
|
+
"Platform hub start response missing an authorization URL",
|
|
125
|
+
502,
|
|
126
|
+
"HUB_INVALID_START_RESPONSE",
|
|
127
|
+
data
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return { authorizationUrl, state: data.state, expiresAt: data.expiresAt, scopes: data.scopes };
|
|
117
131
|
}
|
|
118
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Last-known health for every connection. The platform has no global
|
|
134
|
+
* healthcheck listing — health rides on each connection row — so this derives
|
|
135
|
+
* the list from `listConnections()` (one request, no extra round-trips).
|
|
136
|
+
*/
|
|
119
137
|
async listHealthchecks() {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
138
|
+
const connections = await this.listConnections();
|
|
139
|
+
return connections.map((c) => ({
|
|
140
|
+
connectionId: c.id,
|
|
141
|
+
providerId: c.providerId,
|
|
142
|
+
status: c.health,
|
|
143
|
+
checkedAt: c.updatedAt
|
|
144
|
+
}));
|
|
125
145
|
}
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
146
|
+
/**
|
|
147
|
+
* POST /v1/hub/connections/:connectionId/health — trigger a fresh health
|
|
148
|
+
* probe for one connection and return its updated state.
|
|
149
|
+
*/
|
|
150
|
+
checkConnectionHealth(connectionId) {
|
|
151
|
+
return this.request("POST", `/v1/hub/connections/${encodeURIComponent(connectionId)}/health`);
|
|
129
152
|
}
|
|
130
153
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
154
|
+
* Trigger a fresh health probe across all of the user's connections. The
|
|
155
|
+
* platform exposes health per-connection only, so this fans out over
|
|
156
|
+
* `listConnections()`. `scheduled` is the number of probes dispatched.
|
|
134
157
|
*/
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
async runHealthchecks() {
|
|
159
|
+
const connections = await this.listConnections();
|
|
160
|
+
await Promise.allSettled(connections.map((c) => this.checkConnectionHealth(c.id)));
|
|
161
|
+
return { scheduled: connections.length };
|
|
162
|
+
}
|
|
163
|
+
/** GET /v1/hub/status — principal + aggregate connection counts. */
|
|
164
|
+
status() {
|
|
165
|
+
return this.request("GET", "/v1/hub/status");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* POST /v1/hub/tokens — mint a short-lived, action-scoped capability token a
|
|
169
|
+
* sandbox can use to invoke one hub action on the user's behalf without
|
|
170
|
+
* seeing the underlying provider credential.
|
|
171
|
+
*/
|
|
172
|
+
mintToken(input) {
|
|
173
|
+
return this.request("POST", "/v1/hub/tokens", input);
|
|
174
|
+
}
|
|
175
|
+
/** POST /v1/hub/exec — execute a hub action and return its result. */
|
|
176
|
+
async exec(input) {
|
|
177
|
+
const data = await this.request("POST", "/v1/hub/exec", input);
|
|
178
|
+
return data.result;
|
|
137
179
|
}
|
|
138
180
|
async request(method, path, body) {
|
|
139
181
|
const headers = {
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/platform/auth.ts","../src/platform/integrations.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * `products/platform/api/src/routes/cross-site.ts`. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n user: {\n id: string\n email: string\n name?: string\n }\n plan: {\n tier: string\n }\n}\n\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n const result = body as Partial<ExchangeCodeResult>\n if (!result.apiKey || !result.user?.id) {\n throw new PlatformAuthError(\n 'Platform exchange response is missing apiKey or user',\n res.status,\n body,\n )\n }\n return result as ExchangeCodeResult\n }\n}\n","/**\n * Server-side client for the Tangle platform's integrations hub\n * (`/v1/integrations/*`). Consumer apps use this instead of rolling\n * their own OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n * Per-request override via `headers` is supported.\n *\n * Endpoint contract: `products/platform/api/src/routes/integrations.ts`.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface PlatformConnection {\n id: string\n providerId: string\n connectorId: string\n status: 'connected' | 'pending' | 'revoked' | 'expired' | string\n grantedScopes?: string[]\n account?: { identity?: string; displayName?: string } & Record<string, unknown>\n metadata?: Record<string, unknown>\n expiresAt?: string | null\n createdAt?: string\n updatedAt?: string\n}\n\nexport interface PlatformCatalogProvider {\n providerId: string\n displayName?: string\n description?: string\n authMode?: string\n connectors?: PlatformCatalogConnector[]\n [k: string]: unknown\n}\n\nexport interface PlatformCatalogConnector {\n connectorId: string\n displayName?: string\n description?: string\n scopes?: string[]\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n providerId: string\n connectorId: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n requestedScopes?: string[]\n state?: string\n metadata?: Record<string, unknown>\n /** Required when the bearer is a service token impersonating a user. */\n ownerUserId?: string\n}\n\nexport interface StartAuthResult {\n authorizationUrl: string\n state: string\n}\n\nexport interface BundleCapabilityInput {\n manifestId?: string\n grantIds?: string[]\n subject: { type: 'user' | 'team' | 'app'; id: string }\n ttlMs: number\n}\n\nexport interface BundleCapabilityResult {\n bundle: Record<string, unknown>\n env: Record<string, string>\n}\n\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n connectorId: string\n status: 'ok' | 'degraded' | 'failing' | 'unknown' | string\n checks?: Record<string, unknown>\n checkedAt?: string\n}\n\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /** List the integration catalog (providers + connectors). */\n catalog(): Promise<{ providers: PlatformCatalogProvider[] } & Record<string, unknown>> {\n return this.request('GET', '/v1/integrations/catalog')\n }\n\n /** List the calling user's integration connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/integrations/connections',\n )\n return data.connections\n }\n\n /** Revoke (and disable) a connection by id. */\n revokeConnection(connectionId: string): Promise<{\n connection: PlatformConnection\n revokedGrants: unknown[]\n providerRevocation: { ok: boolean }\n }> {\n return this.request(\n 'DELETE',\n `/v1/integrations/connections/${encodeURIComponent(connectionId)}`,\n )\n }\n\n /** Begin OAuth — returns the URL to send the user to. */\n startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n return this.request('POST', '/v1/integrations/auth/start', input)\n }\n\n /** List connection healthchecks (last known state). */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const data = await this.request<{ healthchecks: HealthCheck[] }>(\n 'GET',\n '/v1/integrations/healthchecks',\n )\n return data.healthchecks\n }\n\n /** Trigger a fresh healthcheck pass. */\n runHealthchecks(): Promise<{ scheduled: number }> {\n return this.request('POST', '/v1/integrations/healthchecks/run', {})\n }\n\n /**\n * Mint a sandbox-injectable capability bundle (env vars + scoped\n * capability tokens) so a sandbox can invoke integrations on the\n * user's behalf without seeing the underlying provider tokens.\n */\n bundleCapabilities(input: BundleCapabilityInput): Promise<BundleCapabilityResult> {\n return this.request('POST', '/v1/integrations/capabilities/bundle', input)\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/platform/auth.ts","../src/platform/integrations.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * `products/platform/api/src/routes/cross-site.ts`. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n user: {\n id: string\n email: string\n name?: string\n }\n plan: {\n tier: string\n }\n}\n\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n const result = body as Partial<ExchangeCodeResult>\n if (!result.apiKey || !result.user?.id) {\n throw new PlatformAuthError(\n 'Platform exchange response is missing apiKey or user',\n res.status,\n body,\n )\n }\n return result as ExchangeCodeResult\n }\n}\n","/**\n * Server-side client for the Tangle platform's integration hub\n * (`/v1/hub/*`). Consumer apps use this instead of rolling their own\n * OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n *\n * Endpoint contract (authoritative): the platform's `src/lib/hub-contract.ts`\n * + `src/routes/hub.ts`. The platform wraps every response in\n * `{ success, data }`; non-2xx or `success:false` surfaces as `PlatformHubError`\n * carrying the real upstream status.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\n/** A live integration connection, as returned by `/v1/hub/connections`. */\nexport interface PlatformConnection {\n id: string\n providerId: string\n displayName: string\n accountDisplay: string | null\n scopes: string[]\n status: 'active' | 'revoked' | 'unhealthy' | 'reconnect_required' | (string & {})\n health: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n createdAt: string\n updatedAt: string\n lastUsedAt: string | null\n}\n\n/** A connectable provider in the catalog (`/v1/hub/providers`). */\nexport interface PlatformCatalogProvider {\n providerId: string\n title?: string\n authKind?: string\n category?: string\n scopes?: string[]\n capabilityCount?: number\n native?: boolean\n /** Whether the OAuth app's credentials are wired — the UI offers Connect\n * only when true. */\n configured?: boolean\n [k: string]: unknown\n}\n\nexport interface CatalogResult {\n providers: PlatformCatalogProvider[]\n /** Count of substrate-bundled connectors behind the catalog. */\n substrateBundled?: number\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n /** The provider to connect (goes in the URL path). */\n providerId: string\n /** Accepted for interface compatibility; the platform's start endpoint is\n * provider-level and does not consume a connector id. */\n connectorId?: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n /** Accepted for interface compatibility; not consumed by the start endpoint. */\n requestedScopes?: string[]\n /** CLI flow flag — affects the platform's post-auth redirect handling. */\n cli?: boolean\n}\n\nexport interface StartAuthResult {\n /** The URL to send the user to. Normalized across the platform's two start\n * branches: github returns `authorizationUrl`, substrate returns\n * `redirectUrl`. */\n authorizationUrl: string\n state: string\n expiresAt?: string\n scopes?: string[]\n}\n\nexport interface ConnectionHealth {\n status: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n checkedAt: string\n error?: { code: string; message: string }\n}\n\nexport interface ConnectionHealthResult {\n connection: PlatformConnection\n health: ConnectionHealth\n}\n\n/** Last-known health for a connection, derived from the connection row. */\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n /** Mirrors `PlatformConnection.health`. */\n status: ConnectionHealth['status']\n checkedAt?: string\n}\n\nexport interface MintTokenInput {\n /** The hub action the token authorizes (e.g. `slack.chat.postMessage`). */\n actionPath: string\n /** Bind to a specific connection, or … */\n connectionId?: string\n /** … resolve the connection by provider for the calling user. */\n provider?: string\n}\n\nexport interface MintTokenResult {\n tokenId: string\n token: string\n expiresAt: string\n}\n\nexport interface ExecInput {\n /** The hub action path to execute. */\n path: string\n input?: unknown\n connectionId?: string\n}\n\nexport interface PlatformHubStatus {\n contract?: unknown\n principal: { kind: string; userId: string; [k: string]: unknown }\n connections: { connectedProviderCount: number; unhealthyProviderCount: number }\n}\n\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /** GET /v1/hub/providers — the connectable provider catalog. */\n catalog(): Promise<CatalogResult> {\n return this.request('GET', '/v1/hub/providers')\n }\n\n /** GET /v1/hub/connections — the calling user's live connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/hub/connections',\n )\n return data.connections\n }\n\n /** DELETE /v1/hub/connections/:connectionId — revoke + disable a connection. */\n revokeConnection(connectionId: string): Promise<{ connection: PlatformConnection }> {\n return this.request('DELETE', `/v1/hub/connections/${encodeURIComponent(connectionId)}`)\n }\n\n /**\n * POST /v1/hub/connections/:provider/start — begin OAuth/grant. The provider\n * is taken from the URL; the body carries `returnUrl` (+ `cli`). The platform's\n * two start branches name the URL field differently (github → `authorizationUrl`,\n * substrate → `redirectUrl`); this normalizes to `authorizationUrl`.\n */\n async startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n const body: { returnUrl: string; cli?: boolean } = { returnUrl: input.returnUrl }\n if (input.cli !== undefined) body.cli = input.cli\n const data = await this.request<{\n authorizationUrl?: string\n redirectUrl?: string\n state: string\n expiresAt?: string\n scopes?: string[]\n }>('POST', `/v1/hub/connections/${encodeURIComponent(input.providerId)}/start`, body)\n const authorizationUrl = data.authorizationUrl ?? data.redirectUrl\n if (!authorizationUrl) {\n throw new PlatformHubError(\n 'Platform hub start response missing an authorization URL',\n 502,\n 'HUB_INVALID_START_RESPONSE',\n data,\n )\n }\n return { authorizationUrl, state: data.state, expiresAt: data.expiresAt, scopes: data.scopes }\n }\n\n /**\n * Last-known health for every connection. The platform has no global\n * healthcheck listing — health rides on each connection row — so this derives\n * the list from `listConnections()` (one request, no extra round-trips).\n */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const connections = await this.listConnections()\n return connections.map((c) => ({\n connectionId: c.id,\n providerId: c.providerId,\n status: c.health,\n checkedAt: c.updatedAt,\n }))\n }\n\n /**\n * POST /v1/hub/connections/:connectionId/health — trigger a fresh health\n * probe for one connection and return its updated state.\n */\n checkConnectionHealth(connectionId: string): Promise<ConnectionHealthResult> {\n return this.request('POST', `/v1/hub/connections/${encodeURIComponent(connectionId)}/health`)\n }\n\n /**\n * Trigger a fresh health probe across all of the user's connections. The\n * platform exposes health per-connection only, so this fans out over\n * `listConnections()`. `scheduled` is the number of probes dispatched.\n */\n async runHealthchecks(): Promise<{ scheduled: number }> {\n const connections = await this.listConnections()\n await Promise.allSettled(connections.map((c) => this.checkConnectionHealth(c.id)))\n return { scheduled: connections.length }\n }\n\n /** GET /v1/hub/status — principal + aggregate connection counts. */\n status(): Promise<PlatformHubStatus> {\n return this.request('GET', '/v1/hub/status')\n }\n\n /**\n * POST /v1/hub/tokens — mint a short-lived, action-scoped capability token a\n * sandbox can use to invoke one hub action on the user's behalf without\n * seeing the underlying provider credential.\n */\n mintToken(input: MintTokenInput): Promise<MintTokenResult> {\n return this.request('POST', '/v1/hub/tokens', input)\n }\n\n /** POST /v1/hub/exec — execute a hub action and return its result. */\n async exec(input: ExecInput): Promise<unknown> {\n const data = await this.request<{ result: unknown }>('POST', '/v1/hub/exec', input)\n return data.result\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/runtime.js
CHANGED
package/dist/workflow.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "Shared task-lifecycle skeleton for agents: a recursive loop kernel for chat turns, one-shot tasks, and multi-attempt loops, with trace capture and eval-gated self-improvement. Domain behavior lives in adapters; scoring and ship-gates in @tangle-network/agent-eval.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-runtime#readme",
|
|
6
6
|
"repository": {
|
|
@@ -39,6 +39,11 @@
|
|
|
39
39
|
"import": "./dist/agent.js",
|
|
40
40
|
"default": "./dist/agent.js"
|
|
41
41
|
},
|
|
42
|
+
"./intelligence": {
|
|
43
|
+
"types": "./dist/intelligence.d.ts",
|
|
44
|
+
"import": "./dist/intelligence.js",
|
|
45
|
+
"default": "./dist/intelligence.js"
|
|
46
|
+
},
|
|
42
47
|
"./runtime": {
|
|
43
48
|
"types": "./dist/runtime.d.ts",
|
|
44
49
|
"import": "./dist/runtime.js",
|