@pylonsync/sdk 0.3.360 → 0.3.362

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/studio.d.ts CHANGED
@@ -211,12 +211,69 @@ export interface BulkAction {
211
211
  /** Hide unless viewer is_admin. */
212
212
  requiresAdmin?: boolean;
213
213
  }
214
+ /**
215
+ * A control attached to every row.
216
+ *
217
+ * `kind: "action"` is the one that calls back into your app: Studio POSTs
218
+ * `/api/fn/<action>` with `input`, then shows the result. Pair it with
219
+ * `display: "button"` for a control that sits in the row instead of behind
220
+ * the `…` menu.
221
+ *
222
+ * @example Generate a share link for a proposal and copy it
223
+ * ```ts
224
+ * rowActions: [
225
+ * {
226
+ * id: "generateLink",
227
+ * label: "Generate link",
228
+ * icon: "link",
229
+ * kind: "action",
230
+ * display: "button",
231
+ * action: "generateProposalLink",
232
+ * input: { proposalId: "{row.id}" },
233
+ * result: "copy",
234
+ * resultField: "url",
235
+ * },
236
+ * ]
237
+ * ```
238
+ */
214
239
  export interface RowAction {
215
240
  id: string;
216
241
  label: string;
217
242
  icon?: IconName;
218
- kind?: "delete" | "edit" | "view" | "custom";
243
+ /**
244
+ * `delete` / `edit` / `view` are built in. `action` calls a server
245
+ * function. `custom` is resolved against `studio.entry.tsx`.
246
+ */
247
+ kind?: "delete" | "edit" | "view" | "action" | "custom";
248
+ /**
249
+ * Where the control renders. `"button"` puts it in the row; `"menu"`
250
+ * (the default) puts it behind the trailing `…` menu.
251
+ */
252
+ display?: "menu" | "button";
253
+ /** Function name for `kind: "action"`. POSTed to `/api/fn/<action>`. */
254
+ action?: string;
255
+ /**
256
+ * Argument object for `kind: "action"`. String values interpolate
257
+ * `{row.<field>}` — a value that is exactly one placeholder keeps the
258
+ * row value's type, so `"{row.count}"` sends a number. Defaults to
259
+ * `{ id: <row id> }`.
260
+ */
261
+ input?: Record<string, unknown>;
262
+ /**
263
+ * What to do with the return value. `"toast"` (default) shows it,
264
+ * `"copy"` writes it to the clipboard, `"dialog"` opens it as JSON,
265
+ * `"none"` discards it.
266
+ */
267
+ result?: "toast" | "copy" | "dialog" | "none";
268
+ /** Dot path into the return value, for `result: "copy"` / `"toast"`. */
269
+ resultField?: string;
270
+ /** Reload the table after the action succeeds. Defaults to true. */
271
+ refresh?: boolean;
272
+ /** Button styling for `display: "button"`. Defaults to `"outline"`. */
273
+ variant?: "default" | "outline" | "ghost" | "secondary" | "destructive";
274
+ /** Confirmation dialog message. Shown before the action runs. */
219
275
  confirm?: string;
276
+ /** Hide unless viewer is_admin. */
220
277
  requiresAdmin?: boolean;
221
278
  }
222
279
  export interface ResourceListConfig {
@@ -270,18 +327,21 @@ export interface StudioConfig {
270
327
  hasExtensions?: boolean;
271
328
  /**
272
329
  * URL to send unauthenticated callers to when they hit `/studio`.
273
- * Lets a host app (Pylon Cloud, an enterprise dashboard) point the
274
- * Studio gate at its own email/password login page instead of the
275
- * built-in `/studio/login` admin-token form.
276
330
  *
277
- * The framework appends `?next=/studio` so the host app can redirect
278
- * back after sign-in. Authenticated-but-not-admin users still see
279
- * the framework's "access denied" page (no point sending them back
280
- * to a login they're already past).
331
+ * Studio requires a signed-in user this app treats as an admin — via
332
+ * `auth.user.adminField` or the `PYLON_ADMIN_EMAILS` allowlist. It has no
333
+ * login page of its own, so point this at yours. Without it, an anonymous
334
+ * visitor gets a static page explaining how to designate an admin, because
335
+ * the framework has no login route it can safely assume you serve.
336
+ *
337
+ * The framework appends `?next=/studio` so the host app can redirect back
338
+ * after sign-in. Authenticated-but-not-admin users still see the
339
+ * framework's "access denied" page — no point sending them back to a login
340
+ * they're already past.
281
341
  *
282
- * Example: `loginUrl: "/login"` — www.pylonsync.com handles `/login`
283
- * at the dashboard, and the user's existing session cookie lifts
284
- * them to admin via `auth.user.adminField` on the way back.
342
+ * Example: `loginUrl: "/login"` — www.pylonsync.com handles `/login` at the
343
+ * dashboard, and the user's existing session cookie lifts them to admin via
344
+ * `auth.user.adminField` on the way back.
285
345
  */
286
346
  loginUrl?: string;
287
347
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.3.360",
6
+ "version": "0.3.362",
7
7
  "type": "module",
8
8
  "main": "./src/index.ts",
9
9
  "types": "./dist/index.d.ts",
package/src/studio.ts CHANGED
@@ -283,12 +283,69 @@ export interface BulkAction {
283
283
  requiresAdmin?: boolean;
284
284
  }
285
285
 
286
+ /**
287
+ * A control attached to every row.
288
+ *
289
+ * `kind: "action"` is the one that calls back into your app: Studio POSTs
290
+ * `/api/fn/<action>` with `input`, then shows the result. Pair it with
291
+ * `display: "button"` for a control that sits in the row instead of behind
292
+ * the `…` menu.
293
+ *
294
+ * @example Generate a share link for a proposal and copy it
295
+ * ```ts
296
+ * rowActions: [
297
+ * {
298
+ * id: "generateLink",
299
+ * label: "Generate link",
300
+ * icon: "link",
301
+ * kind: "action",
302
+ * display: "button",
303
+ * action: "generateProposalLink",
304
+ * input: { proposalId: "{row.id}" },
305
+ * result: "copy",
306
+ * resultField: "url",
307
+ * },
308
+ * ]
309
+ * ```
310
+ */
286
311
  export interface RowAction {
287
312
  id: string;
288
313
  label: string;
289
314
  icon?: IconName;
290
- kind?: "delete" | "edit" | "view" | "custom";
315
+ /**
316
+ * `delete` / `edit` / `view` are built in. `action` calls a server
317
+ * function. `custom` is resolved against `studio.entry.tsx`.
318
+ */
319
+ kind?: "delete" | "edit" | "view" | "action" | "custom";
320
+ /**
321
+ * Where the control renders. `"button"` puts it in the row; `"menu"`
322
+ * (the default) puts it behind the trailing `…` menu.
323
+ */
324
+ display?: "menu" | "button";
325
+ /** Function name for `kind: "action"`. POSTed to `/api/fn/<action>`. */
326
+ action?: string;
327
+ /**
328
+ * Argument object for `kind: "action"`. String values interpolate
329
+ * `{row.<field>}` — a value that is exactly one placeholder keeps the
330
+ * row value's type, so `"{row.count}"` sends a number. Defaults to
331
+ * `{ id: <row id> }`.
332
+ */
333
+ input?: Record<string, unknown>;
334
+ /**
335
+ * What to do with the return value. `"toast"` (default) shows it,
336
+ * `"copy"` writes it to the clipboard, `"dialog"` opens it as JSON,
337
+ * `"none"` discards it.
338
+ */
339
+ result?: "toast" | "copy" | "dialog" | "none";
340
+ /** Dot path into the return value, for `result: "copy"` / `"toast"`. */
341
+ resultField?: string;
342
+ /** Reload the table after the action succeeds. Defaults to true. */
343
+ refresh?: boolean;
344
+ /** Button styling for `display: "button"`. Defaults to `"outline"`. */
345
+ variant?: "default" | "outline" | "ghost" | "secondary" | "destructive";
346
+ /** Confirmation dialog message. Shown before the action runs. */
291
347
  confirm?: string;
348
+ /** Hide unless viewer is_admin. */
292
349
  requiresAdmin?: boolean;
293
350
  }
294
351
 
@@ -351,18 +408,21 @@ export interface StudioConfig {
351
408
  hasExtensions?: boolean;
352
409
  /**
353
410
  * URL to send unauthenticated callers to when they hit `/studio`.
354
- * Lets a host app (Pylon Cloud, an enterprise dashboard) point the
355
- * Studio gate at its own email/password login page instead of the
356
- * built-in `/studio/login` admin-token form.
357
411
  *
358
- * The framework appends `?next=/studio` so the host app can redirect
359
- * back after sign-in. Authenticated-but-not-admin users still see
360
- * the framework's "access denied" page (no point sending them back
361
- * to a login they're already past).
412
+ * Studio requires a signed-in user this app treats as an admin — via
413
+ * `auth.user.adminField` or the `PYLON_ADMIN_EMAILS` allowlist. It has no
414
+ * login page of its own, so point this at yours. Without it, an anonymous
415
+ * visitor gets a static page explaining how to designate an admin, because
416
+ * the framework has no login route it can safely assume you serve.
417
+ *
418
+ * The framework appends `?next=/studio` so the host app can redirect back
419
+ * after sign-in. Authenticated-but-not-admin users still see the
420
+ * framework's "access denied" page — no point sending them back to a login
421
+ * they're already past.
362
422
  *
363
- * Example: `loginUrl: "/login"` — www.pylonsync.com handles `/login`
364
- * at the dashboard, and the user's existing session cookie lifts
365
- * them to admin via `auth.user.adminField` on the way back.
423
+ * Example: `loginUrl: "/login"` — www.pylonsync.com handles `/login` at the
424
+ * dashboard, and the user's existing session cookie lifts them to admin via
425
+ * `auth.user.adminField` on the way back.
366
426
  */
367
427
  loginUrl?: string;
368
428
  }