snow-flow 10.0.186-dev.682 → 10.0.186-dev.694
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/package.json +1 -1
- package/src/cli/cmd/tui/routes/session/index.tsx +3 -1
- package/src/format/index.ts +3 -1
- package/src/plugin/index.ts +4 -1
- package/src/project/agents-template.txt +13 -13
- package/src/project/bootstrap.ts +3 -1
- package/src/servicenow/servicenow-automation-mcp.ts +2 -2
- package/src/servicenow/servicenow-mcp-server.ts +3 -3
- package/src/servicenow/servicenow-mcp-unified/README.md +4 -4
- package/src/servicenow/servicenow-mcp-unified/tools/automation/index.ts +4 -4
- package/src/servicenow/servicenow-mcp-unified/tools/automation/snow_confirm_script_execution.ts +2 -2
- package/src/servicenow/servicenow-mcp-unified/tools/automation/{snow_schedule_script_job.ts → snow_execute_script.ts} +4 -4
- package/src/servicenow/servicenow-mcp-unified/tools/automation/snow_get_script_output.ts +2 -2
- package/src/servicenow/servicenow-mcp-unified/tools/integration/snow_rest_message_manage.ts +4 -4
- package/src/session/message-v2.ts +15 -1
- package/src/share/share-next.ts +45 -40
- package/src/share/share.ts +22 -17
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
For,
|
|
8
8
|
Match,
|
|
9
9
|
on,
|
|
10
|
+
onCleanup,
|
|
10
11
|
onMount,
|
|
11
12
|
Show,
|
|
12
13
|
Switch,
|
|
@@ -202,7 +203,7 @@ export function Session() {
|
|
|
202
203
|
})
|
|
203
204
|
|
|
204
205
|
let lastSwitch: string | undefined = undefined
|
|
205
|
-
sdk.event.on("message.part.updated", (evt) => {
|
|
206
|
+
const unsubPartUpdated = sdk.event.on("message.part.updated", (evt) => {
|
|
206
207
|
const part = evt.properties.part
|
|
207
208
|
if (part.type !== "tool") return
|
|
208
209
|
if (part.sessionID !== route.sessionID) return
|
|
@@ -217,6 +218,7 @@ export function Session() {
|
|
|
217
218
|
lastSwitch = part.id
|
|
218
219
|
}
|
|
219
220
|
})
|
|
221
|
+
onCleanup(() => unsubPartUpdated())
|
|
220
222
|
|
|
221
223
|
let scroll: ScrollBoxRenderable
|
|
222
224
|
let prompt: PromptRef
|
package/src/format/index.ts
CHANGED
|
@@ -100,9 +100,11 @@ export namespace Format {
|
|
|
100
100
|
return result
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
let formatUnsub: (() => void) | undefined
|
|
103
104
|
export function init() {
|
|
104
105
|
log.info("init")
|
|
105
|
-
|
|
106
|
+
formatUnsub?.()
|
|
107
|
+
formatUnsub = Bus.subscribe(File.Event.Edited, async (payload) => {
|
|
106
108
|
const file = payload.properties.file
|
|
107
109
|
log.info("formatting", { file })
|
|
108
110
|
const ext = path.extname(file)
|
package/src/plugin/index.ts
CHANGED
|
@@ -116,6 +116,7 @@ export namespace Plugin {
|
|
|
116
116
|
return state().then((x) => x.hooks)
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
let busUnsub: (() => void) | undefined
|
|
119
120
|
export async function init() {
|
|
120
121
|
const hooks = await state().then((x) => x.hooks)
|
|
121
122
|
const config = await Config.get()
|
|
@@ -123,7 +124,9 @@ export namespace Plugin {
|
|
|
123
124
|
// @ts-expect-error this is because we haven't moved plugin to sdk v2
|
|
124
125
|
await hook.config?.(config)
|
|
125
126
|
}
|
|
126
|
-
|
|
127
|
+
// Clean up previous subscription to prevent accumulation on re-init
|
|
128
|
+
busUnsub?.()
|
|
129
|
+
busUnsub = Bus.subscribeAll(async (input) => {
|
|
127
130
|
const hooks = await state().then((x) => x.hooks)
|
|
128
131
|
for (const hook of hooks) {
|
|
129
132
|
hook["event"]?.({
|
|
@@ -590,23 +590,23 @@ You have **direct access** to MCP tools in your environment. They are **already
|
|
|
590
590
|
- Call the MCP tool directly once discovered
|
|
591
591
|
- Tools work like built-in functions - just call them
|
|
592
592
|
|
|
593
|
-
### Anti-Pattern 2: Using
|
|
593
|
+
### Anti-Pattern 2: Using Script Execution for CRUD Operations
|
|
594
594
|
|
|
595
|
-
|
|
595
|
+
**`snow_execute_script` executes scripts reliably (~1-3s via sync REST API), but prefer dedicated tools for CRUD operations.**
|
|
596
596
|
|
|
597
|
-
|
|
597
|
+
`snow_execute_script` now uses synchronous REST API execution (with scheduler fallback), so it IS reliable for script execution. However, you should still prefer dedicated tools over raw GlideRecord scripts.
|
|
598
598
|
|
|
599
|
-
**
|
|
600
|
-
-
|
|
601
|
-
-
|
|
602
|
-
-
|
|
603
|
-
-
|
|
604
|
-
- ❌ Any operation where you need reliable results
|
|
599
|
+
**Prefer dedicated tools over `snow_execute_script` for:**
|
|
600
|
+
- Querying records → use `snow_query_table`
|
|
601
|
+
- Creating/updating artifacts → use dedicated tools (snow_deploy, snow_update, etc.)
|
|
602
|
+
- Flow operations → use `snow_manage_flow`
|
|
603
|
+
- Checking table/field existence → use `snow_query_table` with limit=1
|
|
605
604
|
|
|
606
|
-
|
|
607
|
-
-
|
|
608
|
-
-
|
|
609
|
-
-
|
|
605
|
+
**`snow_execute_script` IS appropriate for:**
|
|
606
|
+
- ✅ Custom verification scripts that need server-side logic
|
|
607
|
+
- ✅ Complex operations not covered by dedicated tools
|
|
608
|
+
- ✅ Debugging and testing with gs.info output
|
|
609
|
+
- ✅ One-off data operations
|
|
610
610
|
|
|
611
611
|
### Anti-Pattern 3: No Mock Data, No Placeholders
|
|
612
612
|
|
package/src/project/bootstrap.ts
CHANGED
|
@@ -75,9 +75,11 @@ export async function InstanceBootstrap() {
|
|
|
75
75
|
await ensureAgentsMd()
|
|
76
76
|
await ensureInstanceMd()
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
bootstrapUnsub?.()
|
|
79
|
+
bootstrapUnsub = Bus.subscribe(Command.Event.Executed, async (payload) => {
|
|
79
80
|
if (payload.properties.name === Command.Default.INIT) {
|
|
80
81
|
await Project.setInitialized(Instance.project.id)
|
|
81
82
|
}
|
|
82
83
|
})
|
|
83
84
|
}
|
|
85
|
+
let bootstrapUnsub: (() => void) | undefined
|
|
@@ -371,7 +371,7 @@ class ServiceNowAutomationMCP {
|
|
|
371
371
|
{
|
|
372
372
|
name: "snow_schedule_script_with_output",
|
|
373
373
|
description:
|
|
374
|
-
"⚠️ DEPRECATED - Use
|
|
374
|
+
"⚠️ DEPRECATED - Use snow_execute_script instead. SCHEDULES (not executes directly) a script via scheduled job. May return executed=false. ES5 only!",
|
|
375
375
|
inputSchema: {
|
|
376
376
|
type: "object",
|
|
377
377
|
properties: {
|
|
@@ -400,7 +400,7 @@ class ServiceNowAutomationMCP {
|
|
|
400
400
|
{
|
|
401
401
|
name: "snow_schedule_script_sync",
|
|
402
402
|
description:
|
|
403
|
-
'⚠️ DEPRECATED - Use
|
|
403
|
+
'⚠️ DEPRECATED - Use snow_execute_script instead. SCHEDULES (not sync executes) a script via scheduled job. The "sync" name is misleading - this still uses async scheduling. ES5 only!',
|
|
404
404
|
inputSchema: {
|
|
405
405
|
type: "object",
|
|
406
406
|
properties: {
|
|
@@ -220,9 +220,9 @@ class ServiceNowMCPServer {
|
|
|
220
220
|
},
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
|
-
name: "
|
|
223
|
+
name: "snow_execute_script",
|
|
224
224
|
description:
|
|
225
|
-
"
|
|
225
|
+
"Execute server-side JavaScript on ServiceNow. Primary: synchronous execution via Scripted REST API (~1-3s). Fallback: scheduled job if endpoint unavailable. ES5 only (Rhino engine)!",
|
|
226
226
|
inputSchema: {
|
|
227
227
|
type: "object",
|
|
228
228
|
properties: {
|
|
@@ -287,7 +287,7 @@ class ServiceNowMCPServer {
|
|
|
287
287
|
case "snow_create_workflow":
|
|
288
288
|
return await this.handleCreateWorkflow(args)
|
|
289
289
|
|
|
290
|
-
case "
|
|
290
|
+
case "snow_execute_script":
|
|
291
291
|
return await this.handleExecuteScript(args)
|
|
292
292
|
|
|
293
293
|
case "snow_test_connection":
|
|
@@ -51,7 +51,7 @@ servicenow-mcp-unified/
|
|
|
51
51
|
│ │ ├── snow_add_uib_page_element.ts
|
|
52
52
|
│ │ └── index.ts
|
|
53
53
|
│ ├── automation/ # Script execution, jobs
|
|
54
|
-
│ │ ├──
|
|
54
|
+
│ │ ├── snow_execute_script.ts # Execute scripts (sync REST API + scheduler fallback)
|
|
55
55
|
│ │ ├── snow_schedule_job.ts
|
|
56
56
|
│ │ └── index.ts
|
|
57
57
|
│ ├── advanced/ # Analytics
|
|
@@ -110,10 +110,10 @@ Tools are organized by **domain** (functional area), not by original server:
|
|
|
110
110
|
|
|
111
111
|
### 4. Automation Tools (automation/)
|
|
112
112
|
|
|
113
|
-
**Purpose:** Script
|
|
113
|
+
**Purpose:** Script execution and job management
|
|
114
114
|
|
|
115
|
-
- `
|
|
116
|
-
- `snow_confirm_script_execution` - Confirm scripts requiring approval
|
|
115
|
+
- `snow_execute_script` - Execute scripts via synchronous REST API (~1-3s), with scheduler fallback
|
|
116
|
+
- `snow_confirm_script_execution` - Confirm scripts requiring approval
|
|
117
117
|
- `snow_schedule_job` - Create scheduled jobs
|
|
118
118
|
- `snow_get_logs` - Access system logs
|
|
119
119
|
- `snow_trace_execution` - Set up execution tracing configuration
|
|
@@ -34,11 +34,11 @@ export {
|
|
|
34
34
|
toolDefinition as snow_discover_schedules_def,
|
|
35
35
|
execute as snow_discover_schedules_exec,
|
|
36
36
|
} from "./snow_discover_schedules.js"
|
|
37
|
-
//
|
|
37
|
+
// Script execution tool - synchronous REST API execution with scheduler fallback
|
|
38
38
|
export {
|
|
39
|
-
toolDefinition as
|
|
40
|
-
execute as
|
|
41
|
-
} from "./
|
|
39
|
+
toolDefinition as snow_execute_script_def,
|
|
40
|
+
execute as snow_execute_script_exec,
|
|
41
|
+
} from "./snow_execute_script.js"
|
|
42
42
|
export { toolDefinition as snow_get_logs_def, execute as snow_get_logs_exec } from "./snow_get_logs.js"
|
|
43
43
|
export {
|
|
44
44
|
toolDefinition as snow_get_email_logs_def,
|
package/src/servicenow/servicenow-mcp-unified/tools/automation/snow_confirm_script_execution.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* snow_confirm_script_execution - Confirm and execute approved script
|
|
3
3
|
*
|
|
4
4
|
* Executes a script after user approval. Only call this after user
|
|
5
|
-
* explicitly approves script execution from
|
|
5
|
+
* explicitly approves script execution from snow_execute_script with requireConfirmation=true.
|
|
6
6
|
*
|
|
7
7
|
* Uses sysauto_script + sys_trigger approach for reliable execution.
|
|
8
8
|
*
|
|
@@ -16,7 +16,7 @@ import { createSuccessResult, createErrorResult, SnowFlowError, ErrorType } from
|
|
|
16
16
|
export const toolDefinition: MCPToolDefinition = {
|
|
17
17
|
name: "snow_confirm_script_execution",
|
|
18
18
|
description:
|
|
19
|
-
"⚡ Confirms and schedules script after user approval (use after
|
|
19
|
+
"⚡ Confirms and schedules script after user approval (use after snow_execute_script with requireConfirmation=true). Note: Uses same scheduled job approach.",
|
|
20
20
|
// Metadata for tool discovery (not sent to LLM)
|
|
21
21
|
category: "automation",
|
|
22
22
|
subcategory: "script-execution",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* snow_execute_script - Execute server-side JavaScript on ServiceNow
|
|
3
3
|
*
|
|
4
4
|
* Primary: synchronous execution via Scripted REST API (~1-3s)
|
|
5
5
|
* Fallback: scheduled job if endpoint unavailable
|
|
@@ -87,11 +87,11 @@ const OPERATION_SCRIPT = `(function process(request, response) {
|
|
|
87
87
|
})(request, response);`
|
|
88
88
|
|
|
89
89
|
export const toolDefinition: MCPToolDefinition = {
|
|
90
|
-
name: "
|
|
90
|
+
name: "snow_execute_script",
|
|
91
91
|
description:
|
|
92
92
|
"Execute server-side JavaScript on ServiceNow. Primary: synchronous execution via Scripted REST API (~1-3s). Fallback: scheduled job if endpoint unavailable. Auto-deploys the executor endpoint on first use. ES5 only (Rhino engine)!",
|
|
93
93
|
category: "automation",
|
|
94
|
-
subcategory: "
|
|
94
|
+
subcategory: "script-execution",
|
|
95
95
|
use_cases: ["automation", "scripts", "scheduled-jobs", "debugging", "verification"],
|
|
96
96
|
complexity: "advanced",
|
|
97
97
|
frequency: "high",
|
|
@@ -150,7 +150,7 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
150
150
|
|
|
151
151
|
export async function execute(args: Record<string, unknown>, context: ServiceNowContext): Promise<ToolResult> {
|
|
152
152
|
const script = args.script as string
|
|
153
|
-
const description = (args.description as string) || "Script
|
|
153
|
+
const description = (args.description as string) || "Script executed via snow_execute_script"
|
|
154
154
|
const timeout = (args.timeout as number) || 30000
|
|
155
155
|
const validate = args.validate_es5 !== false
|
|
156
156
|
const confirmation = args.requireConfirmation === true
|
|
@@ -46,7 +46,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
46
46
|
const client = await getAuthenticatedClient(context)
|
|
47
47
|
|
|
48
48
|
// Try to find the output in sys_properties
|
|
49
|
-
//
|
|
49
|
+
// snow_execute_script stores output as: SNOW_FLOW_EXEC_${executionId}
|
|
50
50
|
const outputMarker = `SNOW_FLOW_EXEC_${execution_id}`
|
|
51
51
|
|
|
52
52
|
const outputResponse = await client.get(
|
|
@@ -62,7 +62,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
62
62
|
await client.delete(`/api/now/table/sys_properties/${property.sys_id}`)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
// Organize output by level (matches
|
|
65
|
+
// Organize output by level (matches snow_execute_script format)
|
|
66
66
|
const organizedOutput = {
|
|
67
67
|
print: (scriptOutput.output || []).filter((o: any) => o.level === "print").map((o: any) => o.message),
|
|
68
68
|
info: (scriptOutput.output || []).filter((o: any) => o.level === "info").map((o: any) => o.message),
|
|
@@ -27,7 +27,7 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
27
27
|
• Message-level Headers - apply to ALL methods (list_message_headers, create_message_header, delete_message_header)
|
|
28
28
|
• Method-level Headers - apply to specific method (list_method_headers, create_method_header, delete_method_header)
|
|
29
29
|
• Query Parameters (list_parameters, create_parameter, delete_parameter)
|
|
30
|
-
• Testing (test) - generates ES5-compatible test script for
|
|
30
|
+
• Testing (test) - generates ES5-compatible test script for snow_execute_script`,
|
|
31
31
|
// Metadata for tool discovery (not sent to LLM)
|
|
32
32
|
category: "integration",
|
|
33
33
|
subcategory: "rest",
|
|
@@ -1448,11 +1448,11 @@ ${paramLines.length > 0 ? " " + paramLines.join("\n ") : " // No parame
|
|
|
1448
1448
|
test_params_provided: test_params,
|
|
1449
1449
|
test_script: testScript,
|
|
1450
1450
|
usage: {
|
|
1451
|
-
description: "Use
|
|
1452
|
-
example: `
|
|
1451
|
+
description: "Use snow_execute_script to execute this test script",
|
|
1452
|
+
example: `snow_execute_script({ script: <test_script>, description: 'Test REST: ${restMessageName}' })`,
|
|
1453
1453
|
manual_test: `In ServiceNow: System Web Services > Outbound > REST Message > ${restMessageName} > ${method.name} > Test`,
|
|
1454
1454
|
},
|
|
1455
|
-
note: "Direct REST message testing requires ServiceNow script execution. Copy the test_script and run it via
|
|
1455
|
+
note: "Direct REST message testing requires ServiceNow script execution. Copy the test_script and run it via snow_execute_script.",
|
|
1456
1456
|
},
|
|
1457
1457
|
{ operation: "test_rest_message" },
|
|
1458
1458
|
)
|
|
@@ -447,6 +447,8 @@ export namespace MessageV2 {
|
|
|
447
447
|
|
|
448
448
|
// In-memory message cache: avoids re-reading all messages from disk on every loop iteration.
|
|
449
449
|
// Uses Instance.state for per-instance isolation and Bus events for cache invalidation.
|
|
450
|
+
// LRU eviction: only the most recently accessed sessions are kept in memory.
|
|
451
|
+
const MAX_CACHED_SESSIONS = 3
|
|
450
452
|
const messageCache = Instance.state(
|
|
451
453
|
() => {
|
|
452
454
|
const sessions = new Map<string, MessageV2.WithParts[]>()
|
|
@@ -508,7 +510,12 @@ export namespace MessageV2 {
|
|
|
508
510
|
export async function streamCached(sessionID: string): Promise<WithParts[]> {
|
|
509
511
|
const { sessions } = messageCache()
|
|
510
512
|
const existing = sessions.get(sessionID)
|
|
511
|
-
if (existing)
|
|
513
|
+
if (existing) {
|
|
514
|
+
// LRU: move to end (most recently used)
|
|
515
|
+
sessions.delete(sessionID)
|
|
516
|
+
sessions.set(sessionID, existing)
|
|
517
|
+
return existing
|
|
518
|
+
}
|
|
512
519
|
|
|
513
520
|
// Cold start: load from disk and populate cache
|
|
514
521
|
const result: WithParts[] = []
|
|
@@ -517,6 +524,13 @@ export namespace MessageV2 {
|
|
|
517
524
|
}
|
|
518
525
|
result.reverse() // stream yields newest first, we want chronological order
|
|
519
526
|
sessions.set(sessionID, result)
|
|
527
|
+
|
|
528
|
+
// LRU eviction: remove oldest sessions if over limit
|
|
529
|
+
while (sessions.size > MAX_CACHED_SESSIONS) {
|
|
530
|
+
const oldest = sessions.keys().next().value
|
|
531
|
+
if (oldest) sessions.delete(oldest)
|
|
532
|
+
}
|
|
533
|
+
|
|
520
534
|
return result
|
|
521
535
|
}
|
|
522
536
|
|
package/src/share/share-next.ts
CHANGED
|
@@ -17,52 +17,57 @@ export namespace ShareNext {
|
|
|
17
17
|
|
|
18
18
|
const disabled = process.env["OPENCODE_DISABLE_SHARE"] === "true" || process.env["OPENCODE_DISABLE_SHARE"] === "1"
|
|
19
19
|
|
|
20
|
+
const shareNextUnsubs: (() => void)[] = []
|
|
20
21
|
export async function init() {
|
|
21
22
|
if (disabled) return
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data: evt.properties.info as any,
|
|
35
|
-
},
|
|
36
|
-
])
|
|
37
|
-
if (evt.properties.info.role === "user") {
|
|
23
|
+
for (const unsub of shareNextUnsubs) unsub()
|
|
24
|
+
shareNextUnsubs.length = 0
|
|
25
|
+
shareNextUnsubs.push(
|
|
26
|
+
Bus.subscribe(Session.Event.Updated, async (evt) => {
|
|
27
|
+
await sync(evt.properties.info.id, [
|
|
28
|
+
{
|
|
29
|
+
type: "session",
|
|
30
|
+
data: evt.properties.info,
|
|
31
|
+
},
|
|
32
|
+
])
|
|
33
|
+
}),
|
|
34
|
+
Bus.subscribe(MessageV2.Event.Updated, async (evt) => {
|
|
38
35
|
await sync(evt.properties.info.sessionID, [
|
|
39
36
|
{
|
|
40
|
-
type: "
|
|
41
|
-
data:
|
|
42
|
-
await Provider.getModel(evt.properties.info.model.providerID, evt.properties.info.model.modelID).then(
|
|
43
|
-
(m) => m,
|
|
44
|
-
),
|
|
45
|
-
],
|
|
37
|
+
type: "message",
|
|
38
|
+
data: evt.properties.info as any,
|
|
46
39
|
},
|
|
47
40
|
])
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
41
|
+
if (evt.properties.info.role === "user") {
|
|
42
|
+
await sync(evt.properties.info.sessionID, [
|
|
43
|
+
{
|
|
44
|
+
type: "model",
|
|
45
|
+
data: [
|
|
46
|
+
await Provider.getModel(evt.properties.info.model.providerID, evt.properties.info.model.modelID).then(
|
|
47
|
+
(m) => m,
|
|
48
|
+
),
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
])
|
|
52
|
+
}
|
|
53
|
+
}),
|
|
54
|
+
Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
|
55
|
+
await sync(evt.properties.part.sessionID, [
|
|
56
|
+
{
|
|
57
|
+
type: "part",
|
|
58
|
+
data: evt.properties.part,
|
|
59
|
+
},
|
|
60
|
+
])
|
|
61
|
+
}),
|
|
62
|
+
Bus.subscribe(Session.Event.Diff, async (evt) => {
|
|
63
|
+
await sync(evt.properties.sessionID, [
|
|
64
|
+
{
|
|
65
|
+
type: "session_diff",
|
|
66
|
+
data: evt.properties.diff,
|
|
67
|
+
},
|
|
68
|
+
])
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
export async function create(sessionID: string) {
|
package/src/share/share.ts
CHANGED
|
@@ -46,24 +46,29 @@ export namespace Share {
|
|
|
46
46
|
})
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
const shareUnsubs: (() => void)[] = []
|
|
49
50
|
export function init() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
for (const unsub of shareUnsubs) unsub()
|
|
52
|
+
shareUnsubs.length = 0
|
|
53
|
+
shareUnsubs.push(
|
|
54
|
+
Bus.subscribe(Session.Event.Updated, async (evt) => {
|
|
55
|
+
await sync("session/info/" + evt.properties.info.id, evt.properties.info)
|
|
56
|
+
}),
|
|
57
|
+
Bus.subscribe(MessageV2.Event.Updated, async (evt) => {
|
|
58
|
+
await sync("session/message/" + evt.properties.info.sessionID + "/" + evt.properties.info.id, evt.properties.info)
|
|
59
|
+
}),
|
|
60
|
+
Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
|
61
|
+
await sync(
|
|
62
|
+
"session/part/" +
|
|
63
|
+
evt.properties.part.sessionID +
|
|
64
|
+
"/" +
|
|
65
|
+
evt.properties.part.messageID +
|
|
66
|
+
"/" +
|
|
67
|
+
evt.properties.part.id,
|
|
68
|
+
evt.properties.part,
|
|
69
|
+
)
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
export const URL =
|