@rynx-ai/daemon 0.1.11-beta.53 → 0.1.11-beta.54

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/plugin-channel-lark",
3
- "version": "0.1.11-beta.53",
3
+ "version": "0.1.11-beta.54",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -9,7 +9,7 @@ import { PluginRunnerError } from "@rynx-ai/plugin-runner";
9
9
  import { ensurePluginSessionLaunch, replayPluginSessionLaunch, SessionLaunchOperationConflictError, SessionLaunchOperationTargetDeletedError, } from "./session-launch-operations.js";
10
10
  import { createControlLink } from "./control-link-store.js";
11
11
  import { nodeLogFiles, sessionLogFiles } from "./log-files.js";
12
- import { issueSessionPortalTicket, revokeSessionPortalGrant, } from "./session-portal-grant-store.js";
12
+ import { issueSessionPortalTicket, revokeSessionPortalGrant, renewSessionPortalGrant, } from "./session-portal-grant-store.js";
13
13
  import { claimSessionTimelineProjection, completeSessionTimelineProjection, } from "./session-timeline-projection-store.js";
14
14
  const MAX_MESSAGE_LENGTH = 1_000_000;
15
15
  /** Leaves ample room for the RPC envelope below the runner's 1 MiB line cap. */
@@ -134,6 +134,7 @@ export class PluginHostRpc {
134
134
  ? {
135
135
  sessionPortalEmbedOrigin: true,
136
136
  sessionPortalGrantRevocation: true,
137
+ sessionPortalGrantRenewal: true,
137
138
  }
138
139
  : {}),
139
140
  },
@@ -251,6 +252,33 @@ export class PluginHostRpc {
251
252
  this.ownedSession(sessionId);
252
253
  return this.issueSessionPortalLink("single_session", requiredSessionPortalAccess(input), sessionId, optionalSessionPortalEmbedOrigin(input.embedOrigin), optionalString(input.grantHandle, "grantHandle", 128));
253
254
  }
255
+ case "session.portal.grant.renew": {
256
+ const input = record(params);
257
+ const scope = input.scope;
258
+ if (scope !== "single_session" && scope !== "plugin_sessions") {
259
+ throw new PluginHostCallError("INVALID_PARAMS", "scope must be single_session or plugin_sessions");
260
+ }
261
+ const sessionId = scope === "single_session" ? requiredSessionId(input) : undefined;
262
+ if (sessionId)
263
+ this.ownedSession(sessionId);
264
+ else if (input.sessionId !== undefined) {
265
+ throw new PluginHostCallError("INVALID_PARAMS", "plugin_sessions scope cannot specify a Session");
266
+ }
267
+ const embedOrigin = optionalSessionPortalEmbedOrigin(input.embedOrigin);
268
+ if (!embedOrigin)
269
+ throw new PluginHostCallError("INVALID_PARAMS", "embedOrigin is required for renewal");
270
+ const renewed = renewSessionPortalGrant({
271
+ pluginId: this.principalId,
272
+ grantHandle: requiredString(input.grantHandle, "grantHandle", 128),
273
+ scope,
274
+ access: requiredSessionPortalAccess(input),
275
+ sessionId,
276
+ embedOrigin,
277
+ });
278
+ if (!renewed)
279
+ throw new PluginHostCallError("HOST_CALL_FAILED", "Session Portal grant expired, revoked, or does not match the authorized scope");
280
+ return renewed;
281
+ }
254
282
  case "session.portal.grant.revoke": {
255
283
  const grantHandle = requiredString(record(params).grantHandle, "grantHandle", 128);
256
284
  return revokeSessionPortalGrant({
@@ -34,6 +34,20 @@ export declare function redeemSessionPortalTicket(ticket: string, now?: Date, em
34
34
  * exact grant that was issued; it does not authorize an API call. */
35
35
  export declare function inspectSessionPortalGrant(portalId: string, now?: Date): SessionPortalAuthorization | undefined;
36
36
  export declare function authorizeSessionPortalGrant(portalId: string, secret: string, now?: Date): SessionPortalAuthorization | undefined;
37
+ /** Only the issuing Plugin may extend an embedded grant, after its external
38
+ * authorizer has rechecked the viewer's current permissions. Match the freshly
39
+ * authorized scope so an old handle cannot renew another Session or access level. */
40
+ export declare function renewSessionPortalGrant(input: {
41
+ pluginId: string;
42
+ grantHandle: string;
43
+ scope: SessionPortalScope;
44
+ access: SessionPortalAccess;
45
+ sessionId?: string;
46
+ embedOrigin: string;
47
+ now?: Date;
48
+ }): {
49
+ expiresAt: string;
50
+ } | undefined;
37
51
  /** Revoke one issued Portal link, whether its ticket is still unused or it has
38
52
  * already become a browser grant. The opaque handle carries no product meaning. */
39
53
  export declare function revokeSessionPortalGrant(input: {
@@ -91,6 +91,20 @@ export function authorizeSessionPortalGrant(portalId, secret, now = new Date())
91
91
  return undefined;
92
92
  return publicGrant(row);
93
93
  }
94
+ /** Only the issuing Plugin may extend an embedded grant, after its external
95
+ * authorizer has rechecked the viewer's current permissions. Match the freshly
96
+ * authorized scope so an old handle cannot renew another Session or access level. */
97
+ export function renewSessionPortalGrant(input) {
98
+ if (!input.embedOrigin)
99
+ return undefined;
100
+ const now = input.now ?? new Date();
101
+ const expiresAt = new Date(now.getTime() + GRANT_TTL_MS).toISOString();
102
+ const updated = db().prepare(`UPDATE session_portal_grants SET expires_at = ?
103
+ WHERE plugin_id = ? AND grant_handle = ? AND scope = ? AND access = ?
104
+ AND session_id IS ? AND embed_origin = ?
105
+ AND revoked_at IS NULL AND expires_at > ?`).run(expiresAt, input.pluginId, input.grantHandle, input.scope, input.access, input.sessionId ?? null, input.embedOrigin, now.toISOString());
106
+ return updated.changes > 0 ? { expiresAt } : undefined;
107
+ }
94
108
  /** Revoke one issued Portal link, whether its ticket is still unused or it has
95
109
  * already become a browser grant. The opaque handle carries no product meaning. */
96
110
  export async function revokeSessionPortalGrant(input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/daemon",
3
- "version": "0.1.11-beta.53",
3
+ "version": "0.1.11-beta.54",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -60,18 +60,18 @@
60
60
  "tar": "^7.5.19",
61
61
  "undici": "^7.28.0",
62
62
  "ws": "^8.21.0",
63
- "@rynx-ai/core": "0.1.11-beta.53",
64
- "@rynx-ai/emulator": "0.1.11-beta.53",
65
- "@rynx-ai/plugin-runner": "0.1.11-beta.53",
66
- "@rynx-ai/plugin-sdk": "0.1.11-beta.53",
67
- "@rynx-ai/protocol": "0.1.11-beta.53",
68
- "@rynx-ai/remote-runtime-client": "0.1.11-beta.53",
69
- "@rynx-ai/server": "0.1.11-beta.53"
63
+ "@rynx-ai/core": "0.1.11-beta.54",
64
+ "@rynx-ai/emulator": "0.1.11-beta.54",
65
+ "@rynx-ai/plugin-runner": "0.1.11-beta.54",
66
+ "@rynx-ai/plugin-sdk": "0.1.11-beta.54",
67
+ "@rynx-ai/protocol": "0.1.11-beta.54",
68
+ "@rynx-ai/remote-runtime-client": "0.1.11-beta.54",
69
+ "@rynx-ai/server": "0.1.11-beta.54"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/ws": "^8.18.1",
73
- "@rynx-ai/browser-cdp": "0.1.11-beta.53",
74
- "@rynx-ai/plugin-channel-lark": "0.1.11-beta.53"
73
+ "@rynx-ai/browser-cdp": "0.1.11-beta.54",
74
+ "@rynx-ai/plugin-channel-lark": "0.1.11-beta.54"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "rm -rf dist bundled-plugins && tsc -p tsconfig.json && chmod +x dist/index-daemon.js && node scripts/prepare-agent-browser.mjs && node ../../scripts/stage-bundled-plugins.mjs && node scripts/build-plugin-maintenance.mjs",