@pylonsync/sdk 0.22.28 → 0.22.30
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/index.d.ts +44 -13
- package/package.json +1 -1
- package/src/connection.test.ts +35 -0
- package/src/index.ts +50 -13
package/dist/index.d.ts
CHANGED
|
@@ -1185,40 +1185,63 @@ export type ManifestLlmConfig = {
|
|
|
1185
1185
|
/**
|
|
1186
1186
|
* Developer-facing config for `defineConnection({...})`. Each entry
|
|
1187
1187
|
* adds a `ctx.connections.<name>` surface to mutation + action ctx
|
|
1188
|
-
* (server-side
|
|
1188
|
+
* (server-side tokens and keys, never visible to the browser).
|
|
1189
1189
|
*
|
|
1190
|
-
* `provider` selects the
|
|
1191
|
-
* built-in list (`google`, `github`, `slack`, `microsoft`, etc.)
|
|
1192
|
-
*
|
|
1193
|
-
* the
|
|
1190
|
+
* `provider` selects the provider: a sign-in provider from pylon-auth's
|
|
1191
|
+
* built-in list (`google`, `github`, `slack`, `microsoft`, etc.) or a
|
|
1192
|
+
* business integration (`square`, `stripe`, `clover`, `calendly`,
|
|
1193
|
+
* `mailchimp`). `name` is the app-facing key — different connections
|
|
1194
|
+
* can target the same provider with different scopes
|
|
1194
1195
|
* (e.g. `google-calendar` vs `google-drive`).
|
|
1195
1196
|
*
|
|
1197
|
+
* `owner: "app"` makes one connection for the whole app — the
|
|
1198
|
+
* business's own Square or Stripe account — that any server function
|
|
1199
|
+
* reads (including for an anonymous visitor) and only an admin changes.
|
|
1200
|
+
* The default `owner: "user"` links each signed-in user's own account.
|
|
1201
|
+
*
|
|
1202
|
+
* `kind: "api_key"` stores key fields instead of running OAuth (Toast's
|
|
1203
|
+
* Standard API access, a Stripe restricted key). `fields` names them;
|
|
1204
|
+
* the default is the provider's own list (`stripe`: `secretKey`,
|
|
1205
|
+
* `square`: `accessToken`, `toast`: `clientId`, `clientSecret`,
|
|
1206
|
+
* `restaurantGuid`), else `apiKey`.
|
|
1207
|
+
*
|
|
1196
1208
|
* Configuration: per-provider client id + secret come from env
|
|
1197
1209
|
* (`PYLON_OAUTH_<PROVIDER>_CLIENT_ID`, `PYLON_OAUTH_<PROVIDER>_CLIENT_SECRET`).
|
|
1198
1210
|
* Callback URL is derived from `PYLON_PUBLIC_URL` +
|
|
1199
|
-
* `/api/connections/<name>/callback`.
|
|
1211
|
+
* `/api/connections/<name>/callback`. On a platform that brokers
|
|
1212
|
+
* connections (`PYLON_CONNECTIONS_BROKER_URL`), the platform runs the
|
|
1213
|
+
* OAuth flow for app connections and the app needs no client secret.
|
|
1200
1214
|
*
|
|
1201
1215
|
* Storage: the framework auto-creates a `_Connection` entity at
|
|
1202
|
-
* boot when any connection is declared; token fields are AEAD-
|
|
1216
|
+
* boot when any connection is declared; token and key fields are AEAD-
|
|
1203
1217
|
* encrypted at rest (`PYLON_ENCRYPTION_KEY` is REQUIRED — boot
|
|
1204
1218
|
* fails without it when connections are declared).
|
|
1205
1219
|
*/
|
|
1206
1220
|
export type ConnectionConfig = {
|
|
1207
1221
|
/** App-facing key. `ctx.connections.get(name)` matches on this. */
|
|
1208
1222
|
name: string;
|
|
1209
|
-
/** Provider identifier
|
|
1223
|
+
/** Provider identifier: a pylon-auth OAuth provider or an integration. */
|
|
1210
1224
|
provider: string;
|
|
1211
1225
|
/** Whitespace-separated scopes. Empty = provider default. */
|
|
1212
1226
|
scopes?: string;
|
|
1227
|
+
/** `"user"` (default) or `"app"`. */
|
|
1228
|
+
owner?: "user" | "app";
|
|
1229
|
+
/** `"oauth"` (default) or `"api_key"`. */
|
|
1230
|
+
kind?: "oauth" | "api_key";
|
|
1231
|
+
/** API-key field names, for `kind: "api_key"`. */
|
|
1232
|
+
fields?: string[];
|
|
1213
1233
|
};
|
|
1214
1234
|
export type ManifestConnection = {
|
|
1215
1235
|
name: string;
|
|
1216
1236
|
provider: string;
|
|
1217
1237
|
scopes?: string;
|
|
1238
|
+
owner?: "user" | "app";
|
|
1239
|
+
kind?: "oauth" | "api_key";
|
|
1240
|
+
fields?: string[];
|
|
1218
1241
|
};
|
|
1219
1242
|
/**
|
|
1220
|
-
* Declare a server-side
|
|
1221
|
-
*
|
|
1243
|
+
* Declare a server-side integration. Returns the manifest entry the
|
|
1244
|
+
* runtime parses. Re-exported through `app.ts`:
|
|
1222
1245
|
*
|
|
1223
1246
|
* ```ts
|
|
1224
1247
|
* import { defineConnection } from "@pylonsync/sdk";
|
|
@@ -1228,11 +1251,19 @@ export type ManifestConnection = {
|
|
|
1228
1251
|
* provider: "google",
|
|
1229
1252
|
* scopes: "email profile https://www.googleapis.com/auth/calendar.readonly",
|
|
1230
1253
|
* });
|
|
1254
|
+
*
|
|
1255
|
+
* // The business's Square account, used by the store's checkout.
|
|
1256
|
+
* export const square = defineConnection({
|
|
1257
|
+
* name: "square",
|
|
1258
|
+
* provider: "square",
|
|
1259
|
+
* owner: "app",
|
|
1260
|
+
* scopes: "ITEMS_READ ITEMS_WRITE INVENTORY_READ INVENTORY_WRITE ORDERS_WRITE PAYMENTS_WRITE",
|
|
1261
|
+
* });
|
|
1231
1262
|
* ```
|
|
1232
1263
|
*
|
|
1233
|
-
* `buildManifest({ connections: [googleConn] })` carries
|
|
1234
|
-
* the manifest; the runtime auto-creates the `_Connection` entity
|
|
1235
|
-
* and exposes `ctx.connections.get("
|
|
1264
|
+
* `buildManifest({ connections: [googleConn, square] })` carries these
|
|
1265
|
+
* into the manifest; the runtime auto-creates the `_Connection` entity
|
|
1266
|
+
* and exposes `ctx.connections.get("square")` to actions.
|
|
1236
1267
|
*/
|
|
1237
1268
|
export declare function defineConnection(cfg: ConnectionConfig): ManifestConnection;
|
|
1238
1269
|
/**
|
package/package.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { defineConnection } from "./index";
|
|
3
|
+
|
|
4
|
+
describe("defineConnection", () => {
|
|
5
|
+
test("leaves defaults out of the manifest", () => {
|
|
6
|
+
expect(defineConnection({ name: "google", provider: "google", owner: "user", kind: "oauth" })).toEqual({
|
|
7
|
+
name: "google",
|
|
8
|
+
provider: "google",
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("carries an app connection and its key fields", () => {
|
|
13
|
+
expect(
|
|
14
|
+
defineConnection({
|
|
15
|
+
name: "toast",
|
|
16
|
+
provider: "toast",
|
|
17
|
+
owner: "app",
|
|
18
|
+
kind: "api_key",
|
|
19
|
+
fields: ["clientId", "clientSecret", "restaurantGuid"],
|
|
20
|
+
}),
|
|
21
|
+
).toEqual({
|
|
22
|
+
name: "toast",
|
|
23
|
+
provider: "toast",
|
|
24
|
+
owner: "app",
|
|
25
|
+
kind: "api_key",
|
|
26
|
+
fields: ["clientId", "clientSecret", "restaurantGuid"],
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("refuses fields on an OAuth connection", () => {
|
|
31
|
+
expect(() => defineConnection({ name: "sq", provider: "square", fields: ["x"] })).toThrow(
|
|
32
|
+
/fields apply to kind "api_key" only/,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -2145,42 +2145,65 @@ export type ManifestLlmConfig = {
|
|
|
2145
2145
|
/**
|
|
2146
2146
|
* Developer-facing config for `defineConnection({...})`. Each entry
|
|
2147
2147
|
* adds a `ctx.connections.<name>` surface to mutation + action ctx
|
|
2148
|
-
* (server-side
|
|
2148
|
+
* (server-side tokens and keys, never visible to the browser).
|
|
2149
2149
|
*
|
|
2150
|
-
* `provider` selects the
|
|
2151
|
-
* built-in list (`google`, `github`, `slack`, `microsoft`, etc.)
|
|
2152
|
-
*
|
|
2153
|
-
* the
|
|
2150
|
+
* `provider` selects the provider: a sign-in provider from pylon-auth's
|
|
2151
|
+
* built-in list (`google`, `github`, `slack`, `microsoft`, etc.) or a
|
|
2152
|
+
* business integration (`square`, `stripe`, `clover`, `calendly`,
|
|
2153
|
+
* `mailchimp`). `name` is the app-facing key — different connections
|
|
2154
|
+
* can target the same provider with different scopes
|
|
2154
2155
|
* (e.g. `google-calendar` vs `google-drive`).
|
|
2155
2156
|
*
|
|
2157
|
+
* `owner: "app"` makes one connection for the whole app — the
|
|
2158
|
+
* business's own Square or Stripe account — that any server function
|
|
2159
|
+
* reads (including for an anonymous visitor) and only an admin changes.
|
|
2160
|
+
* The default `owner: "user"` links each signed-in user's own account.
|
|
2161
|
+
*
|
|
2162
|
+
* `kind: "api_key"` stores key fields instead of running OAuth (Toast's
|
|
2163
|
+
* Standard API access, a Stripe restricted key). `fields` names them;
|
|
2164
|
+
* the default is the provider's own list (`stripe`: `secretKey`,
|
|
2165
|
+
* `square`: `accessToken`, `toast`: `clientId`, `clientSecret`,
|
|
2166
|
+
* `restaurantGuid`), else `apiKey`.
|
|
2167
|
+
*
|
|
2156
2168
|
* Configuration: per-provider client id + secret come from env
|
|
2157
2169
|
* (`PYLON_OAUTH_<PROVIDER>_CLIENT_ID`, `PYLON_OAUTH_<PROVIDER>_CLIENT_SECRET`).
|
|
2158
2170
|
* Callback URL is derived from `PYLON_PUBLIC_URL` +
|
|
2159
|
-
* `/api/connections/<name>/callback`.
|
|
2171
|
+
* `/api/connections/<name>/callback`. On a platform that brokers
|
|
2172
|
+
* connections (`PYLON_CONNECTIONS_BROKER_URL`), the platform runs the
|
|
2173
|
+
* OAuth flow for app connections and the app needs no client secret.
|
|
2160
2174
|
*
|
|
2161
2175
|
* Storage: the framework auto-creates a `_Connection` entity at
|
|
2162
|
-
* boot when any connection is declared; token fields are AEAD-
|
|
2176
|
+
* boot when any connection is declared; token and key fields are AEAD-
|
|
2163
2177
|
* encrypted at rest (`PYLON_ENCRYPTION_KEY` is REQUIRED — boot
|
|
2164
2178
|
* fails without it when connections are declared).
|
|
2165
2179
|
*/
|
|
2166
2180
|
export type ConnectionConfig = {
|
|
2167
2181
|
/** App-facing key. `ctx.connections.get(name)` matches on this. */
|
|
2168
2182
|
name: string;
|
|
2169
|
-
/** Provider identifier
|
|
2183
|
+
/** Provider identifier: a pylon-auth OAuth provider or an integration. */
|
|
2170
2184
|
provider: string;
|
|
2171
2185
|
/** Whitespace-separated scopes. Empty = provider default. */
|
|
2172
2186
|
scopes?: string;
|
|
2187
|
+
/** `"user"` (default) or `"app"`. */
|
|
2188
|
+
owner?: "user" | "app";
|
|
2189
|
+
/** `"oauth"` (default) or `"api_key"`. */
|
|
2190
|
+
kind?: "oauth" | "api_key";
|
|
2191
|
+
/** API-key field names, for `kind: "api_key"`. */
|
|
2192
|
+
fields?: string[];
|
|
2173
2193
|
};
|
|
2174
2194
|
|
|
2175
2195
|
export type ManifestConnection = {
|
|
2176
2196
|
name: string;
|
|
2177
2197
|
provider: string;
|
|
2178
2198
|
scopes?: string;
|
|
2199
|
+
owner?: "user" | "app";
|
|
2200
|
+
kind?: "oauth" | "api_key";
|
|
2201
|
+
fields?: string[];
|
|
2179
2202
|
};
|
|
2180
2203
|
|
|
2181
2204
|
/**
|
|
2182
|
-
* Declare a server-side
|
|
2183
|
-
*
|
|
2205
|
+
* Declare a server-side integration. Returns the manifest entry the
|
|
2206
|
+
* runtime parses. Re-exported through `app.ts`:
|
|
2184
2207
|
*
|
|
2185
2208
|
* ```ts
|
|
2186
2209
|
* import { defineConnection } from "@pylonsync/sdk";
|
|
@@ -2190,17 +2213,31 @@ export type ManifestConnection = {
|
|
|
2190
2213
|
* provider: "google",
|
|
2191
2214
|
* scopes: "email profile https://www.googleapis.com/auth/calendar.readonly",
|
|
2192
2215
|
* });
|
|
2216
|
+
*
|
|
2217
|
+
* // The business's Square account, used by the store's checkout.
|
|
2218
|
+
* export const square = defineConnection({
|
|
2219
|
+
* name: "square",
|
|
2220
|
+
* provider: "square",
|
|
2221
|
+
* owner: "app",
|
|
2222
|
+
* scopes: "ITEMS_READ ITEMS_WRITE INVENTORY_READ INVENTORY_WRITE ORDERS_WRITE PAYMENTS_WRITE",
|
|
2223
|
+
* });
|
|
2193
2224
|
* ```
|
|
2194
2225
|
*
|
|
2195
|
-
* `buildManifest({ connections: [googleConn] })` carries
|
|
2196
|
-
* the manifest; the runtime auto-creates the `_Connection` entity
|
|
2197
|
-
* and exposes `ctx.connections.get("
|
|
2226
|
+
* `buildManifest({ connections: [googleConn, square] })` carries these
|
|
2227
|
+
* into the manifest; the runtime auto-creates the `_Connection` entity
|
|
2228
|
+
* and exposes `ctx.connections.get("square")` to actions.
|
|
2198
2229
|
*/
|
|
2199
2230
|
export function defineConnection(cfg: ConnectionConfig): ManifestConnection {
|
|
2231
|
+
if (cfg.fields && cfg.fields.length > 0 && cfg.kind !== "api_key") {
|
|
2232
|
+
throw new Error(`defineConnection("${cfg.name}"): fields apply to kind "api_key" only`);
|
|
2233
|
+
}
|
|
2200
2234
|
return {
|
|
2201
2235
|
name: cfg.name,
|
|
2202
2236
|
provider: cfg.provider,
|
|
2203
2237
|
...(cfg.scopes ? { scopes: cfg.scopes } : {}),
|
|
2238
|
+
...(cfg.owner && cfg.owner !== "user" ? { owner: cfg.owner } : {}),
|
|
2239
|
+
...(cfg.kind && cfg.kind !== "oauth" ? { kind: cfg.kind } : {}),
|
|
2240
|
+
...(cfg.fields && cfg.fields.length > 0 ? { fields: [...cfg.fields] } : {}),
|
|
2204
2241
|
};
|
|
2205
2242
|
}
|
|
2206
2243
|
|