@dxos/plugin-thread 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.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/PLUGIN.mdl +122 -1
- package/dist/lib/ChannelBackend.mjs +46 -3
- package/dist/lib/ChannelBackend.mjs.map +1 -1
- package/dist/lib/ThreadCapabilities.mjs.map +1 -1
- package/dist/lib/ThreadOperation.mjs +101 -4
- package/dist/lib/ThreadOperation.mjs.map +1 -1
- package/dist/lib/ThreadOperationHandlerSet.mjs +19 -0
- package/dist/lib/ThreadOperationHandlerSet.mjs.map +1 -0
- package/dist/lib/capabilities.browser.mjs +36 -0
- package/dist/lib/capabilities.browser.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +8 -5
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.node.mjs +6 -1
- package/dist/lib/capabilities.node.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +36 -0
- package/dist/lib/capabilities.tauri.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs +6 -1
- package/dist/lib/capabilities.workerd.mjs.map +1 -1
- package/dist/lib/chunk-ChannelArticle.mjs +16 -19
- package/dist/lib/chunk-ChannelArticle.mjs.map +1 -1
- package/dist/lib/chunk-ChannelCreatePanel.mjs +5 -4
- package/dist/lib/chunk-ChannelCreatePanel.mjs.map +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +6 -0
- package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
- package/dist/lib/chunk-ThreadArticle.mjs +13 -8
- package/dist/lib/chunk-ThreadArticle.mjs.map +1 -1
- package/dist/lib/chunk-app-graph-builder.mjs +7 -4
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -1
- package/dist/lib/chunk-append-channel-message.mjs +3 -14
- package/dist/lib/chunk-append-channel-message.mjs.map +1 -1
- package/dist/lib/chunk-channel-backend-feed.mjs +8 -18
- package/dist/lib/chunk-channel-backend-feed.mjs.map +1 -1
- package/dist/lib/chunk-connect-channel.mjs +14 -0
- package/dist/lib/chunk-connect-channel.mjs.map +1 -0
- package/dist/lib/chunk-create-channel.mjs +1 -1
- package/dist/lib/chunk-create-object.mjs +1 -1
- package/dist/lib/chunk-disconnect-channel.mjs +14 -0
- package/dist/lib/chunk-disconnect-channel.mjs.map +1 -0
- package/dist/lib/chunk-get-channel-status.mjs +14 -0
- package/dist/lib/chunk-get-channel-status.mjs.map +1 -0
- package/dist/lib/chunk-open-direct.mjs +15 -0
- package/dist/lib/chunk-open-direct.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +2 -2
- package/dist/lib/chunk-operation-handler.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +2 -2
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/chunk-send-to-channel.mjs +28 -0
- package/dist/lib/chunk-send-to-channel.mjs.map +1 -0
- package/dist/lib/components.mjs +9 -7
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/containers.mjs.map +1 -1
- package/dist/lib/hooks.mjs +4 -3
- package/dist/lib/hooks.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -4
- package/dist/lib/meta.mjs +1 -0
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/operations.mjs +2 -9
- package/dist/lib/translations.mjs +1 -1
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/types/src/capabilities/channel-backend-feed.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/browser.d.ts +10 -0
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/node.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/tauri.d.ts +10 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/components/MessageThread/MessageThread.d.ts +2 -2
- package/dist/types/src/components/MessageThread/MessageThread.d.ts.map +1 -1
- package/dist/types/src/components/MessageThread/index.d.ts +1 -1
- package/dist/types/src/components/MessageThread/index.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts +1 -1
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.stories.d.ts +1 -1
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelArticle/index.d.ts +1 -1
- package/dist/types/src/containers/ChannelArticle/index.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelCreatePanel/ChannelCreatePanel.d.ts +1 -1
- package/dist/types/src/containers/ChannelCreatePanel/ChannelCreatePanel.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelCreatePanel/index.d.ts +1 -1
- package/dist/types/src/containers/ChannelCreatePanel/index.d.ts.map +1 -1
- package/dist/types/src/containers/ThreadArticle/ThreadArticle.d.ts +2 -2
- package/dist/types/src/containers/ThreadArticle/ThreadArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ThreadArticle/index.d.ts +1 -1
- package/dist/types/src/containers/ThreadArticle/index.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useStatus.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/operations/ThreadOperationHandlerSet.d.ts +3 -0
- package/dist/types/src/operations/ThreadOperationHandlerSet.d.ts.map +1 -0
- package/dist/types/src/operations/append-channel-message.d.ts.map +1 -1
- package/dist/types/src/operations/channel-operations.test.d.ts +2 -0
- package/dist/types/src/operations/channel-operations.test.d.ts.map +1 -0
- package/dist/types/src/operations/connect-channel.d.ts +5 -0
- package/dist/types/src/operations/connect-channel.d.ts.map +1 -0
- package/dist/types/src/operations/disconnect-channel.d.ts +5 -0
- package/dist/types/src/operations/disconnect-channel.d.ts.map +1 -0
- package/dist/types/src/operations/get-channel-status.d.ts +5 -0
- package/dist/types/src/operations/get-channel-status.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +1 -2
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/open-direct.d.ts +5 -0
- package/dist/types/src/operations/open-direct.d.ts.map +1 -0
- package/dist/types/src/operations/send-to-channel.d.ts +5 -0
- package/dist/types/src/operations/send-to-channel.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/ChannelBackend.d.ts +79 -1
- package/dist/types/src/types/ChannelBackend.d.ts.map +1 -1
- package/dist/types/src/types/ThreadCapabilities.d.ts +30 -4
- package/dist/types/src/types/ThreadCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/ThreadOperation.d.ts +78 -2
- package/dist/types/src/types/ThreadOperation.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +4 -4
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +3 -0
- package/package.json +53 -40
- package/src/capabilities/app-graph-builder.ts +3 -2
- package/src/capabilities/channel-backend-feed.ts +5 -10
- package/src/capabilities/gen/browser.ts +57 -0
- package/src/capabilities/gen/node.ts +5 -5
- package/src/capabilities/gen/tauri.ts +57 -0
- package/src/capabilities/gen/workerd.ts +5 -5
- package/src/capabilities/index.ts +8 -8
- package/src/capabilities/operation-handler.ts +1 -1
- package/src/capabilities/react-surface.ts +2 -2
- package/src/components/MessageThread/MessageThread.tsx +11 -14
- package/src/components/MessageThread/index.ts +1 -1
- package/src/components/index.ts +1 -1
- package/src/containers/ChannelArticle/ChannelArticle.stories.tsx +4 -4
- package/src/containers/ChannelArticle/ChannelArticle.tsx +17 -20
- package/src/containers/ChannelArticle/index.ts +1 -1
- package/src/containers/ChannelCreatePanel/ChannelCreatePanel.tsx +10 -5
- package/src/containers/ChannelCreatePanel/index.ts +1 -1
- package/src/containers/ThreadArticle/ThreadArticle.stories.tsx +7 -7
- package/src/containers/ThreadArticle/ThreadArticle.tsx +21 -12
- package/src/containers/ThreadArticle/index.ts +1 -1
- package/src/containers/index.ts +3 -3
- package/src/hooks/index.ts +2 -2
- package/src/hooks/useMessages.ts +2 -2
- package/src/hooks/useStatus.ts +4 -1
- package/src/index.ts +2 -4
- package/src/meta.ts +1 -1
- package/src/operations/ThreadOperationHandlerSet.ts +20 -0
- package/src/operations/append-channel-message.ts +2 -6
- package/src/operations/channel-operations.test.ts +185 -0
- package/src/operations/connect-channel.ts +23 -0
- package/src/operations/disconnect-channel.ts +23 -0
- package/src/operations/get-channel-status.ts +23 -0
- package/src/operations/index.ts +1 -9
- package/src/operations/open-direct.ts +32 -0
- package/src/operations/send-to-channel.ts +33 -0
- package/src/plugin.test.ts +3 -3
- package/src/translations.ts +2 -2
- package/src/types/ChannelBackend.test.ts +2 -2
- package/src/types/ChannelBackend.ts +66 -2
- package/src/types/ThreadCapabilities.ts +41 -4
- package/src/types/ThreadOperation.ts +114 -5
- package/src/types/index.ts +4 -4
- package/dist/lib/chunk-paths.mjs +0 -8
- package/dist/lib/chunk-paths.mjs.map +0 -1
- package/dist/lib/operations.mjs.map +0 -1
package/PLUGIN.mdl
CHANGED
|
@@ -18,7 +18,8 @@ The following extension dialects are used in this document.
|
|
|
18
18
|
|-------------|--------------------------------|
|
|
19
19
|
| `type` | `org.dxos.mdl.type@1.0` |
|
|
20
20
|
| `feat` | `org.dxos.mdl.feat@1.0` |
|
|
21
|
-
| `op` | `org.dxos.mdl.op@1.
|
|
21
|
+
| `op` | `org.dxos.mdl.op@1.1` |
|
|
22
|
+
| `test` | `org.dxos.mdl.test@1.0` |
|
|
22
23
|
|
|
23
24
|
## Types
|
|
24
25
|
|
|
@@ -58,6 +59,48 @@ op AppendChannelMessage
|
|
|
58
59
|
text: String
|
|
59
60
|
```
|
|
60
61
|
|
|
62
|
+
```mdl
|
|
63
|
+
op SendToChannel
|
|
64
|
+
key: org.dxos.operation.thread.sendToChannel
|
|
65
|
+
desc: |
|
|
66
|
+
Send text to a channel, or to a backend thread inside it, through the provider resolved by
|
|
67
|
+
`channel.backend.kind`. A backend refusal returns `delivered: false` with a reason; a missing
|
|
68
|
+
provider or a backend without threads fails with a typed error.
|
|
69
|
+
in:
|
|
70
|
+
channel: Ref<Channel>
|
|
71
|
+
thread?: String
|
|
72
|
+
text: String
|
|
73
|
+
out:
|
|
74
|
+
delivered: Boolean
|
|
75
|
+
messageIds?: String[]
|
|
76
|
+
properties?: Record
|
|
77
|
+
reason?: String
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```mdl
|
|
81
|
+
op OpenDirect
|
|
82
|
+
key: org.dxos.operation.thread.openDirect
|
|
83
|
+
desc: |
|
|
84
|
+
Open a direct conversation (a DM) with a Person through the channel's account, via the
|
|
85
|
+
backend's optional `openDirect`; returns a thread id for SendToChannel.
|
|
86
|
+
in:
|
|
87
|
+
channel: Ref<Channel>
|
|
88
|
+
person: Ref<Person>
|
|
89
|
+
out:
|
|
90
|
+
thread?: String
|
|
91
|
+
reason?: String
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```mdl
|
|
95
|
+
op ConnectChannel
|
|
96
|
+
key: org.dxos.operation.thread.connectChannel
|
|
97
|
+
desc: Start the backend's optional connection (a bot gateway); DisconnectChannel and GetChannelStatus stop and report it.
|
|
98
|
+
in:
|
|
99
|
+
channel: Ref<Channel>
|
|
100
|
+
out:
|
|
101
|
+
status: ConnectionStatus
|
|
102
|
+
```
|
|
103
|
+
|
|
61
104
|
## Features
|
|
62
105
|
|
|
63
106
|
```mdl
|
|
@@ -73,3 +116,81 @@ feat F-2: Thread chat
|
|
|
73
116
|
req F-2.1: A Thread article MUST render the thread's messages and append new
|
|
74
117
|
messages by pushing onto `thread.messages`.
|
|
75
118
|
```
|
|
119
|
+
|
|
120
|
+
## QA
|
|
121
|
+
|
|
122
|
+
Executable tests. Each step carries a human instruction (`do`) and, where the step maps to an
|
|
123
|
+
invocable operation, an agent binding (`invoke`). Report failures by test and step number.
|
|
124
|
+
|
|
125
|
+
```mdl
|
|
126
|
+
test QA-1: Create a channel and send a message
|
|
127
|
+
desc: The core thread round-trip — create a Channel, send a message, read it back from the feed.
|
|
128
|
+
actors: both
|
|
129
|
+
covers: [F-1.1]
|
|
130
|
+
status: unverified
|
|
131
|
+
given:
|
|
132
|
+
- identityDid: an identity exists, its DID used as the message `sender`
|
|
133
|
+
- space: a space is open
|
|
134
|
+
- no Channel named "QA Channel" exists — ABORT rather than deleting one this test did not create
|
|
135
|
+
steps:
|
|
136
|
+
- name: Create the channel
|
|
137
|
+
do: In the navtree, click + on the space and choose Channel. Name it "QA Channel".
|
|
138
|
+
invoke: [op:CreateChannel] { spaceId: $given.space.id, name: "QA Channel" }
|
|
139
|
+
capture: created
|
|
140
|
+
expect: a Channel named "QA Channel" now exists and opens in the channel article
|
|
141
|
+
assert: return !!$created.object
|
|
142
|
+
- name: Place it in the space
|
|
143
|
+
do: (no separate gesture — the navtree create action places it)
|
|
144
|
+
invoke: org.dxos.operation.space.addObject { object: $created.object, target: $given.space }
|
|
145
|
+
expect: "QA Channel" appears as a row in the navtree
|
|
146
|
+
- name: Send a message
|
|
147
|
+
do: In the composer at the bottom of the channel article, type "Hello QA" and press Enter.
|
|
148
|
+
invoke: |
|
|
149
|
+
org.dxos.operation.thread.appendChannelMessage {
|
|
150
|
+
channel: $created.object,
|
|
151
|
+
sender: { identityDid: $given.identityDid },
|
|
152
|
+
text: "Hello QA"
|
|
153
|
+
}
|
|
154
|
+
expect: "Hello QA" appears as the newest (bottom-most) message in the feed
|
|
155
|
+
note: |
|
|
156
|
+
`output: void` — Rule 3 applies: verify the effect, not the return value. Reading the
|
|
157
|
+
feed's queue is not expressible as a synchronous DOM/db snippet here, so this step is
|
|
158
|
+
judged by `expect` alone.
|
|
159
|
+
after:
|
|
160
|
+
- name: Delete the channel
|
|
161
|
+
do: Right-click "QA Channel" in the navtree and choose Delete.
|
|
162
|
+
invoke: org.dxos.operation.space.removeObjects { objects: [$created.object], target: $given.space }
|
|
163
|
+
expect: the row leaves the navtree and its plank closes if it was open
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```mdl
|
|
167
|
+
test QA-2: Default "General" channel on space creation
|
|
168
|
+
desc: The lifecycle hook that seeds every new space with a channel — no user gesture involved.
|
|
169
|
+
actors: agent
|
|
170
|
+
covers: []
|
|
171
|
+
status: unverified
|
|
172
|
+
given:
|
|
173
|
+
- an identity exists
|
|
174
|
+
steps:
|
|
175
|
+
- name: Create a new space
|
|
176
|
+
do: Click "Create space" (or invoke the equivalent action).
|
|
177
|
+
invoke: org.dxos.operation.space.create {}
|
|
178
|
+
capture: created
|
|
179
|
+
expect: a new space is created
|
|
180
|
+
assert: return !!$created.space
|
|
181
|
+
- name: Confirm the default channel exists
|
|
182
|
+
do: Open the new space's navtree and look for a "General" channel.
|
|
183
|
+
expect: a Channel named "General" exists in the root collection of the new space
|
|
184
|
+
note: |
|
|
185
|
+
NO separate `invoke` — `org.dxos.plugin.thread.operation.onCreateSpace` is a lifecycle
|
|
186
|
+
hook the space-creation pipeline runs itself, not something this test calls directly; this
|
|
187
|
+
step only verifies the effect.
|
|
188
|
+
assert: |
|
|
189
|
+
return (await $created.space.db.query(dxos.Filter.type(Channel)).run())
|
|
190
|
+
.objects.some((c) => c.name === 'General');
|
|
191
|
+
after:
|
|
192
|
+
- name: Delete the space
|
|
193
|
+
do: Right-click the new space in the navtree and choose Delete space.
|
|
194
|
+
invoke: org.dxos.operation.space.delete { space: $created.space }
|
|
195
|
+
expect: the space leaves the navtree
|
|
196
|
+
```
|
|
@@ -1,14 +1,57 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { ChannelBackend } from "./ThreadCapabilities.mjs";
|
|
3
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
4
|
+
import { Filter, Query } from "@dxos/echo";
|
|
5
|
+
import { Message } from "@dxos/types";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
2
7
|
import * as Schema from "effect/Schema";
|
|
3
|
-
import
|
|
8
|
+
import * as SchemaAST from "@dxos/effect/SchemaAST";
|
|
9
|
+
import { BaseError } from "@dxos/errors";
|
|
4
10
|
//#region src/types/ChannelBackend.ts
|
|
5
11
|
var ChannelBackend_exports = /* @__PURE__ */ __exportAll({
|
|
12
|
+
ChannelBackendNotFoundError: () => ChannelBackendNotFoundError,
|
|
13
|
+
ChannelBackendUnsupportedError: () => ChannelBackendUnsupportedError,
|
|
6
14
|
assertUniqueKinds: () => assertUniqueKinds,
|
|
7
15
|
buildChannelFormSchema: () => buildChannelFormSchema,
|
|
8
|
-
|
|
16
|
+
getProvider: () => getProvider,
|
|
17
|
+
requireMember: () => requireMember,
|
|
18
|
+
resolveProvider: () => resolveProvider,
|
|
19
|
+
subscribeFeed: () => subscribeFeed,
|
|
20
|
+
toReceipt: () => toReceipt
|
|
9
21
|
});
|
|
22
|
+
/** No contributed provider handles the channel's `backend.kind` (its plugin is disabled or absent). */
|
|
23
|
+
var ChannelBackendNotFoundError = class extends BaseError.extend("ChannelBackendNotFoundError", "No channel backend handles this channel.") {};
|
|
24
|
+
/** The channel's backend lacks an optional member the caller needs (`openDirect`, `threads`, `connection`). */
|
|
25
|
+
var ChannelBackendUnsupportedError = class extends BaseError.extend("ChannelBackendUnsupportedError", "The channel backend does not support this.") {};
|
|
10
26
|
/** Finds the provider matching a `Channel.backend.kind`. */
|
|
11
27
|
var resolveProvider = (providers, kind) => providers.find((provider) => provider.kind === kind);
|
|
28
|
+
/** The contributed provider for a channel, or a typed failure naming the missing kind. */
|
|
29
|
+
var getProvider = Effect.fnUntraced(function* (channel) {
|
|
30
|
+
const provider = resolveProvider(yield* Capability.getAll(ChannelBackend), channel.backend.kind);
|
|
31
|
+
if (!provider) return yield* Effect.fail(new ChannelBackendNotFoundError({ context: { kind: channel.backend.kind } }));
|
|
32
|
+
return provider;
|
|
33
|
+
});
|
|
34
|
+
/** Narrows a provider to one that has the optional member `name`, or fails naming what is missing. */
|
|
35
|
+
var requireMember = (provider, name) => {
|
|
36
|
+
const member = provider[name];
|
|
37
|
+
return member === void 0 ? Effect.fail(new ChannelBackendUnsupportedError({
|
|
38
|
+
message: `The ${provider.label} channel backend does not support ${name}.`,
|
|
39
|
+
context: {
|
|
40
|
+
kind: provider.kind,
|
|
41
|
+
member: name
|
|
42
|
+
}
|
|
43
|
+
})) : Effect.succeed(member);
|
|
44
|
+
};
|
|
45
|
+
/** A provider's send result as a receipt; a backend with nothing to report yields an empty one. */
|
|
46
|
+
var toReceipt = (result) => typeof result === "object" ? result : {};
|
|
47
|
+
/**
|
|
48
|
+
* Subscribes to the messages appended to a feed, firing immediately; returns the unsubscribe.
|
|
49
|
+
* Shared by every backend whose messages live in (or are mirrored into) an ECHO feed.
|
|
50
|
+
*/
|
|
51
|
+
var subscribeFeed = (db, feed, onMessages) => {
|
|
52
|
+
const result = db.query(Query.select(Filter.type(Message.Message)).from(feed));
|
|
53
|
+
return result.subscribe(() => onMessages(result.results), { fire: true });
|
|
54
|
+
};
|
|
12
55
|
/** Throws if two providers share a `kind` (which would make resolution order-dependent). */
|
|
13
56
|
var assertUniqueKinds = (providers) => {
|
|
14
57
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -37,6 +80,6 @@ var buildChannelFormSchema = (providers) => {
|
|
|
37
80
|
};
|
|
38
81
|
var fieldCount = (schema) => SchemaAST.getPropertySignatures(schema.ast).length;
|
|
39
82
|
//#endregion
|
|
40
|
-
export { assertUniqueKinds, buildChannelFormSchema, resolveProvider, ChannelBackend_exports as t };
|
|
83
|
+
export { ChannelBackendNotFoundError, ChannelBackendUnsupportedError, assertUniqueKinds, buildChannelFormSchema, getProvider, requireMember, resolveProvider, subscribeFeed, ChannelBackend_exports as t, toReceipt };
|
|
41
84
|
|
|
42
85
|
//# sourceMappingURL=ChannelBackend.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChannelBackend.mjs","names":[],"sources":["../../src/types/ChannelBackend.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport {
|
|
1
|
+
{"version":3,"file":"ChannelBackend.mjs","names":[],"sources":["../../src/types/ChannelBackend.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { type Database, type Feed, Filter, Query } from '@dxos/echo';\nimport * as SchemaAST from '@dxos/effect/SchemaAST';\nimport { BaseError } from '@dxos/errors';\nimport { type Channel, Message } from '@dxos/types';\n\nimport * as ThreadCapabilities from './ThreadCapabilities.ts';\nimport type * as ThreadOperation from './ThreadOperation.ts';\n\n/** No contributed provider handles the channel's `backend.kind` (its plugin is disabled or absent). */\nexport class ChannelBackendNotFoundError extends BaseError.extend(\n 'ChannelBackendNotFoundError',\n 'No channel backend handles this channel.',\n) {}\n\n/** The channel's backend lacks an optional member the caller needs (`openDirect`, `threads`, `connection`). */\nexport class ChannelBackendUnsupportedError extends BaseError.extend(\n 'ChannelBackendUnsupportedError',\n 'The channel backend does not support this.',\n) {}\n\n/** Finds the provider matching a `Channel.backend.kind`. */\nexport const resolveProvider = (\n providers: readonly ThreadCapabilities.ChannelBackendProvider[],\n kind: string,\n): ThreadCapabilities.ChannelBackendProvider | undefined => providers.find((provider) => provider.kind === kind);\n\n/** The contributed provider for a channel, or a typed failure naming the missing kind. */\nexport const getProvider: (\n channel: Channel.Channel,\n) => Effect.Effect<ThreadCapabilities.ChannelBackendProvider, ChannelBackendNotFoundError, Capability.Service> =\n Effect.fnUntraced(function* (channel) {\n const providers = yield* Capability.getAll(ThreadCapabilities.ChannelBackend);\n const provider = resolveProvider(providers, channel.backend.kind);\n if (!provider) {\n return yield* Effect.fail(new ChannelBackendNotFoundError({ context: { kind: channel.backend.kind } }));\n }\n return provider;\n });\n\n/** Narrows a provider to one that has the optional member `name`, or fails naming what is missing. */\nexport const requireMember = <K extends 'openDirect' | 'threads' | 'connection'>(\n provider: ThreadCapabilities.ChannelBackendProvider,\n name: K,\n): Effect.Effect<NonNullable<ThreadCapabilities.ChannelBackendProvider[K]>, ChannelBackendUnsupportedError> => {\n const member = provider[name];\n return member === undefined\n ? Effect.fail(\n new ChannelBackendUnsupportedError({\n message: `The ${provider.label} channel backend does not support ${name}.`,\n context: { kind: provider.kind, member: name },\n }),\n )\n : Effect.succeed(member);\n};\n\n/** A provider's send result as a receipt; a backend with nothing to report yields an empty one. */\nexport const toReceipt = (result: ThreadCapabilities.SendResult): ThreadOperation.SendReceipt =>\n typeof result === 'object' ? result : {};\n\n/**\n * Subscribes to the messages appended to a feed, firing immediately; returns the unsubscribe.\n * Shared by every backend whose messages live in (or are mirrored into) an ECHO feed.\n */\nexport const subscribeFeed = (\n db: Database.Database,\n feed: Feed.Feed,\n onMessages: (messages: readonly Message.Message[]) => void,\n): (() => void) => {\n const result = db.query(Query.select(Filter.type(Message.Message)).from(feed));\n return result.subscribe(() => onMessages(result.results), { fire: true });\n};\n\n/** Throws if two providers share a `kind` (which would make resolution order-dependent). */\nexport const assertUniqueKinds = (providers: readonly ThreadCapabilities.ChannelBackendProvider[]): void => {\n const seen = new Set<string>();\n for (const provider of providers) {\n if (seen.has(provider.kind)) {\n throw new Error(`Duplicate channel backend kind: ${provider.kind}`);\n }\n seen.add(provider.kind);\n }\n};\n\n/**\n * Builds the create-channel form schema from the registered providers.\n *\n * With a single provider whose create-fields are empty the form is just a\n * `name` field (today's behaviour). With multiple providers (or extra fields)\n * it becomes `{ name?, backend: Union(<{ kind: Literal(p.kind) } & p.createFields>) }`,\n * which react-ui-form renders as a `kind` Select plus the selected branch's fields.\n */\nexport const buildChannelFormSchema = (\n providers: readonly ThreadCapabilities.ChannelBackendProvider[],\n): Schema.Codec<any, any> => {\n assertUniqueKinds(providers);\n const needsSelector = providers.length > 1 || providers.some((provider) => fieldCount(provider.createFields) > 0);\n if (!needsSelector) {\n return Schema.Struct({ name: Schema.optional(Schema.String) });\n }\n\n // `SchemaAST.assignFields`, not `mapFields`: a provider's `createFields` is a `Codec`, which\n // carries no field literals for a struct operation.\n const branches = providers.map((provider) =>\n Schema.make<Schema.Codec<any, any>>(\n SchemaAST.assignFields(Schema.Struct({ kind: Schema.Literal(provider.kind) }).ast, provider.createFields.ast),\n ),\n );\n const backend = branches.length === 1 ? branches[0] : Schema.Union(branches);\n return Schema.Struct({\n name: Schema.optional(Schema.String),\n backend,\n });\n};\n\nconst fieldCount = (schema: Schema.Codec<any, any>): number => SchemaAST.getPropertySignatures(schema.ast).length;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiBA,IAAa,8BAAb,cAAiD,UAAU,OACzD,+BACA,0CACF,CAAC,CAAC,CAAC;;AAGH,IAAa,iCAAb,cAAoD,UAAU,OAC5D,kCACA,4CACF,CAAC,CAAC,CAAC;;AAGH,IAAa,mBACX,WACA,SAC0D,UAAU,MAAM,aAAa,SAAS,SAAS,IAAI;;AAG/G,IAAa,cAGX,OAAO,WAAW,WAAW,SAAS;CAEpC,MAAM,WAAW,gBAAgB,OADR,WAAW,OAAO,cAAiC,GAChC,QAAQ,QAAQ,IAAI;CAChE,IAAI,CAAC,UACH,OAAO,OAAO,OAAO,KAAK,IAAI,4BAA4B,EAAE,SAAS,EAAE,MAAM,QAAQ,QAAQ,KAAK,EAAE,CAAC,CAAC;CAExG,OAAO;AACT,CAAC;;AAGH,IAAa,iBACX,UACA,SAC6G;CAC7G,MAAM,SAAS,SAAS;CACxB,OAAO,WAAW,KAAA,IACd,OAAO,KACL,IAAI,+BAA+B;EACjC,SAAS,OAAO,SAAS,MAAM,oCAAoC,KAAK;EACxE,SAAS;GAAE,MAAM,SAAS;GAAM,QAAQ;EAAK;CAC/C,CAAC,CACH,IACA,OAAO,QAAQ,MAAM;AAC3B;;AAGA,IAAa,aAAa,WACxB,OAAO,WAAW,WAAW,SAAS,CAAC;;;;;AAMzC,IAAa,iBACX,IACA,MACA,eACiB;CACjB,MAAM,SAAS,GAAG,MAAM,MAAM,OAAO,OAAO,KAAK,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC7E,OAAO,OAAO,gBAAgB,WAAW,OAAO,OAAO,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1E;;AAGA,IAAa,qBAAqB,cAA0E;CAC1G,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,YAAY,WAAW;EAChC,IAAI,KAAK,IAAI,SAAS,IAAI,GACxB,MAAM,IAAI,MAAM,mCAAmC,SAAS,MAAM;EAEpE,KAAK,IAAI,SAAS,IAAI;CACxB;AACF;;;;;;;;;AAUA,IAAa,0BACX,cAC2B;CAC3B,kBAAkB,SAAS;CAE3B,IAAI,EADkB,UAAU,SAAS,KAAK,UAAU,MAAM,aAAa,WAAW,SAAS,YAAY,IAAI,CAAC,IAE9G,OAAO,OAAO,OAAO,EAAE,MAAM,OAAO,SAAS,OAAO,MAAM,EAAE,CAAC;CAK/D,MAAM,WAAW,UAAU,KAAK,aAC9B,OAAO,KACL,UAAU,aAAa,OAAO,OAAO,EAAE,MAAM,OAAO,QAAQ,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,aAAa,GAAG,CAC9G,CACF;CACA,MAAM,UAAU,SAAS,WAAW,IAAI,SAAS,KAAK,OAAO,MAAM,QAAQ;CAC3E,OAAO,OAAO,OAAO;EACnB,MAAM,OAAO,SAAS,OAAO,MAAM;EACnC;CACF,CAAC;AACH;AAEA,IAAM,cAAc,WAA2C,UAAU,sBAAsB,OAAO,GAAG,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadCapabilities.mjs","names":[],"sources":["../../src/types/ThreadCapabilities.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Effect from 'effect/Effect';\nimport type * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { type Obj } from '@dxos/echo';\nimport { type Channel, type Message } from '@dxos/types';\n\nimport { meta } from '#meta';\n\n/**\n * A pluggable message backend for a `Channel`. Providers are contributed by\n * plugins and resolved by `Channel.backend.kind`.\n */\nexport interface ChannelBackendProvider {\n /** Stable backend id; matches `Channel.backend.kind`. */\n kind: string;\n /** Human-readable label shown in the create-channel form. */\n label: string;\n /** Icon name (phosphor) for the create-channel form. */\n icon?: string;\n /**\n * Per-backend create-form inputs (a struct; excludes the `kind` discriminant\n * and the channel `name`, which the panel adds). Empty struct when the backend\n * needs no extra input (e.g. the local feed).\n */\n createFields: Schema.Codec<any, any>;\n /** Builds the provider's config object from the collected create-form inputs. */\n makeConfig: (options: Record<string, unknown>) => Obj.Any;\n /**\n * Subscribes to the channel's messages. Invokes `onMessages` with the current\n * list immediately and on every change. Returns an unsubscribe function.\n */\n subscribe: (channel: Channel.Channel, onMessages: (messages: readonly Message.Message[]) => void) => () => void;\n /** Sends a message through the backend. */\n send: (channel: Channel.Channel, message: Message.Message) => Effect.Effect<
|
|
1
|
+
{"version":3,"file":"ThreadCapabilities.mjs","names":[],"sources":["../../src/types/ThreadCapabilities.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport type * as Effect from 'effect/Effect';\nimport type * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { type Obj } from '@dxos/echo';\nimport { type Channel, type Message, type Person } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport type * as ThreadOperation from './ThreadOperation.ts';\n\n/** What a backend reports about a post; `void` when it has nothing to report. */\nexport type SendResult = ThreadOperation.SendReceipt | void;\n\n/**\n * Threads inside a channel, for backends that have them (Discord threads and DM channels).\n * Thread ids are backend-scoped strings, always paired with the channel they belong to.\n */\nexport interface ChannelThreads {\n send: (\n channel: Channel.Channel,\n thread: string,\n message: Message.Message,\n ) => Effect.Effect<SendResult, Error, Capability.Service>;\n}\n\n/** A connection that must be started (a bot gateway, an IRC socket). */\nexport interface ChannelConnection {\n start: (channel: Channel.Channel) => Effect.Effect<ThreadOperation.ConnectionStatus, Error, Capability.Service>;\n stop: (channel: Channel.Channel) => Effect.Effect<ThreadOperation.ConnectionStatus, Error, Capability.Service>;\n status: (channel: Channel.Channel) => Effect.Effect<ThreadOperation.ConnectionStatus, Error, Capability.Service>;\n}\n\n/**\n * A pluggable message backend for a `Channel`. Providers are contributed by\n * plugins and resolved by `Channel.backend.kind`.\n */\nexport interface ChannelBackendProvider {\n /** Stable backend id; matches `Channel.backend.kind`. */\n kind: string;\n /** Human-readable label shown in the create-channel form. */\n label: string;\n /** Icon name (phosphor) for the create-channel form. */\n icon?: string;\n /**\n * Per-backend create-form inputs (a struct; excludes the `kind` discriminant\n * and the channel `name`, which the panel adds). Empty struct when the backend\n * needs no extra input (e.g. the local feed).\n */\n createFields: Schema.Codec<any, any>;\n /** Builds the provider's config object from the collected create-form inputs. */\n makeConfig: (options: Record<string, unknown>) => Obj.Any;\n /**\n * Subscribes to the channel's messages. Invokes `onMessages` with the current\n * list immediately and on every change. Returns an unsubscribe function.\n */\n subscribe: (channel: Channel.Channel, onMessages: (messages: readonly Message.Message[]) => void) => () => void;\n /** Sends a message through the backend; fails with a reason a person can act on. */\n send: (channel: Channel.Channel, message: Message.Message) => Effect.Effect<SendResult, Error, Capability.Service>;\n /** Whether the channel is read-only. Defaults to \"channel has foreign-key Obj.Meta\". */\n readOnly?: (channel: Channel.Channel) => boolean;\n /**\n * Opens a direct conversation with a person through the channel's account (a Discord DM),\n * returning its thread id; `undefined` when the person has no handle this backend knows.\n * The person's handle is the backend's business, read from `Person.identities`.\n */\n openDirect?: (\n channel: Channel.Channel,\n person: Person.Person,\n ) => Effect.Effect<string | undefined, Error, Capability.Service>;\n /** Threads inside the channel (Discord threads and DM channels). */\n threads?: ChannelThreads;\n /** A connection that must be started; absent means the backend is always available. */\n connection?: ChannelConnection;\n}\n\n/** Registry of channel-message backends. Collect with `Capability.getAll`. */\nexport const ChannelBackend = Capability.make<ChannelBackendProvider>()(\n `${meta.profile.key}.capability.channelBackend`,\n);\n"],"mappings":";;;;;;AAmFA,IAAa,iBAAiB,WAAW,KAA6B,CAAC,CACrE,GAAG,KAAK,QAAQ,IAAI,2BACtB"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
2
|
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
-
import { Actor, Channel } from "@dxos/types";
|
|
4
3
|
import * as Operation from "@dxos/compute/Operation";
|
|
5
|
-
import { DXN, Key, Type } from "@dxos/echo";
|
|
4
|
+
import { DXN, Database, Key, Ref, Type } from "@dxos/echo";
|
|
5
|
+
import { Actor, Channel, Person } from "@dxos/types";
|
|
6
6
|
import * as Schema from "effect/Schema";
|
|
7
7
|
//#region src/types/ThreadOperation.ts
|
|
8
8
|
var ThreadOperation_exports = /* @__PURE__ */ __exportAll({
|
|
9
9
|
AppendChannelMessage: () => AppendChannelMessage,
|
|
10
|
-
|
|
10
|
+
ConnectChannel: () => ConnectChannel,
|
|
11
|
+
ConnectionStatus: () => ConnectionStatus,
|
|
12
|
+
CreateChannel: () => CreateChannel,
|
|
13
|
+
DisconnectChannel: () => DisconnectChannel,
|
|
14
|
+
GetChannelStatus: () => GetChannelStatus,
|
|
15
|
+
OpenDirect: () => OpenDirect,
|
|
16
|
+
SendReceipt: () => SendReceipt,
|
|
17
|
+
SendToChannel: () => SendToChannel
|
|
11
18
|
});
|
|
12
19
|
var CreateChannel = Operation.make({
|
|
13
20
|
meta: {
|
|
@@ -40,7 +47,97 @@ var AppendChannelMessage = Operation.make({
|
|
|
40
47
|
}),
|
|
41
48
|
output: Schema.Void
|
|
42
49
|
});
|
|
50
|
+
/**
|
|
51
|
+
* What a backend reports about a message it posted. `properties` are stamped on the copy a caller
|
|
52
|
+
* records locally, so a mirror of that record (EDGE's Discord bot) can tell it was already posted.
|
|
53
|
+
*/
|
|
54
|
+
var SendReceipt = Schema.Struct({
|
|
55
|
+
messageIds: Schema.optional(Schema.Array(Schema.String).annotate({ description: "Backend ids of the posts." })),
|
|
56
|
+
properties: Schema.optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
57
|
+
});
|
|
58
|
+
/** Whether a backend's connection (a bot gateway, an IRC socket) is up. */
|
|
59
|
+
var ConnectionStatus = Schema.Struct({
|
|
60
|
+
running: Schema.Boolean,
|
|
61
|
+
/** Backend-specific state name, e.g. a gateway's `connecting` or `ready`. */
|
|
62
|
+
state: Schema.optional(Schema.String),
|
|
63
|
+
detail: Schema.optional(Schema.String.annotate({ description: "A short human-readable summary." })),
|
|
64
|
+
error: Schema.optional(Schema.String.annotate({ description: "Why the connection last failed." }))
|
|
65
|
+
});
|
|
66
|
+
/** Sends text to a channel, or to a thread inside it, through the channel's backend. */
|
|
67
|
+
var SendToChannel = Operation.make({
|
|
68
|
+
meta: {
|
|
69
|
+
key: DXN.make("org.dxos.operation.thread.sendToChannel"),
|
|
70
|
+
name: "Send to channel",
|
|
71
|
+
description: "Sends a message to a channel, or to a thread inside it, through the channel's backend.",
|
|
72
|
+
icon: "ph--paper-plane-tilt--regular"
|
|
73
|
+
},
|
|
74
|
+
services: [Database.Service, Capability.Service],
|
|
75
|
+
input: Schema.Struct({
|
|
76
|
+
channel: Ref.Ref(Channel.Channel).annotate({ description: "The channel to send to." }),
|
|
77
|
+
thread: Schema.optional(Schema.String.annotate({ description: "A backend-scoped thread id (a Discord thread or DM channel id)." })),
|
|
78
|
+
text: Schema.String.annotate({ description: "The message." })
|
|
79
|
+
}),
|
|
80
|
+
output: Schema.Struct({
|
|
81
|
+
delivered: Schema.Boolean,
|
|
82
|
+
...SendReceipt.fields,
|
|
83
|
+
reason: Schema.optional(Schema.String.annotate({ description: "Why the message was not delivered." }))
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
/** Opens (or finds) a direct conversation with a person through the channel's account. */
|
|
87
|
+
var OpenDirect = Operation.make({
|
|
88
|
+
meta: {
|
|
89
|
+
key: DXN.make("org.dxos.operation.thread.openDirect"),
|
|
90
|
+
name: "Open direct conversation",
|
|
91
|
+
description: "Opens a direct conversation (a DM) with a person through the channel's account; returns its thread id.",
|
|
92
|
+
icon: "ph--user-circle--regular"
|
|
93
|
+
},
|
|
94
|
+
services: [Database.Service, Capability.Service],
|
|
95
|
+
input: Schema.Struct({
|
|
96
|
+
channel: Ref.Ref(Channel.Channel).annotate({ description: "The channel whose account sends the direct message." }),
|
|
97
|
+
person: Ref.Ref(Person.Person).annotate({ description: "The person to reach." })
|
|
98
|
+
}),
|
|
99
|
+
output: Schema.Struct({
|
|
100
|
+
thread: Schema.optional(Schema.String.annotate({ description: "The direct thread id; pass it to sendToChannel as `thread`." })),
|
|
101
|
+
reason: Schema.optional(Schema.String.annotate({ description: "Why the person cannot be reached directly." }))
|
|
102
|
+
})
|
|
103
|
+
});
|
|
104
|
+
/** Starts the channel's connection (or reconfigures a running one). */
|
|
105
|
+
var ConnectChannel = Operation.make({
|
|
106
|
+
meta: {
|
|
107
|
+
key: DXN.make("org.dxos.operation.thread.connectChannel"),
|
|
108
|
+
name: "Connect channel",
|
|
109
|
+
description: "Starts the channel backend's connection, e.g. a bot gateway.",
|
|
110
|
+
icon: "ph--play--regular"
|
|
111
|
+
},
|
|
112
|
+
services: [Database.Service, Capability.Service],
|
|
113
|
+
input: Schema.Struct({ channel: Ref.Ref(Channel.Channel).annotate({ description: "The channel to connect." }) }),
|
|
114
|
+
output: Schema.Struct({ status: ConnectionStatus })
|
|
115
|
+
});
|
|
116
|
+
/** Stops the channel's connection. */
|
|
117
|
+
var DisconnectChannel = Operation.make({
|
|
118
|
+
meta: {
|
|
119
|
+
key: DXN.make("org.dxos.operation.thread.disconnectChannel"),
|
|
120
|
+
name: "Disconnect channel",
|
|
121
|
+
description: "Stops the channel backend's connection.",
|
|
122
|
+
icon: "ph--stop--regular"
|
|
123
|
+
},
|
|
124
|
+
services: [Database.Service, Capability.Service],
|
|
125
|
+
input: Schema.Struct({ channel: Ref.Ref(Channel.Channel).annotate({ description: "The channel to disconnect." }) }),
|
|
126
|
+
output: Schema.Struct({ status: ConnectionStatus })
|
|
127
|
+
});
|
|
128
|
+
/** Reports the channel's connection status. */
|
|
129
|
+
var GetChannelStatus = Operation.make({
|
|
130
|
+
meta: {
|
|
131
|
+
key: DXN.make("org.dxos.operation.thread.getChannelStatus"),
|
|
132
|
+
name: "Get channel status",
|
|
133
|
+
description: "Reports whether the channel backend's connection is up.",
|
|
134
|
+
icon: "ph--pulse--regular"
|
|
135
|
+
},
|
|
136
|
+
services: [Database.Service, Capability.Service],
|
|
137
|
+
input: Schema.Struct({ channel: Ref.Ref(Channel.Channel).annotate({ description: "The channel to report on." }) }),
|
|
138
|
+
output: Schema.Struct({ status: ConnectionStatus })
|
|
139
|
+
});
|
|
43
140
|
//#endregion
|
|
44
|
-
export { AppendChannelMessage, CreateChannel, ThreadOperation_exports as t };
|
|
141
|
+
export { AppendChannelMessage, ConnectChannel, ConnectionStatus, CreateChannel, DisconnectChannel, GetChannelStatus, OpenDirect, SendReceipt, SendToChannel, ThreadOperation_exports as t };
|
|
45
142
|
|
|
46
143
|
//# sourceMappingURL=ThreadOperation.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadOperation.mjs","names":[],"sources":["../../src/types/ThreadOperation.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { DXN, Key, Type } from '@dxos/echo';\
|
|
1
|
+
{"version":3,"file":"ThreadOperation.mjs","names":[],"sources":["../../src/types/ThreadOperation.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, DXN, Key, Ref, Type } from '@dxos/echo';\nimport { Actor, Channel, Person } from '@dxos/types';\n\nexport const CreateChannel = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.createChannel'),\n name: 'Create Channel',\n icon: 'ph--hash--regular',\n },\n services: [Capability.Service],\n input: Schema.Struct({\n spaceId: Key.SpaceId,\n name: Schema.optional(Schema.String),\n /** Backend provider id; defaults to the local feed backend. */\n kind: Schema.optional(Schema.String),\n /** Per-backend create options passed to the provider's makeConfig. */\n options: Schema.optional(Schema.Record(Schema.String, Schema.Any)),\n }),\n output: Schema.Struct({\n object: Type.getSchema(Channel.Channel),\n }),\n});\n\nexport const AppendChannelMessage = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.appendChannelMessage'),\n name: 'Append Channel Message',\n icon: 'ph--chat-text--regular',\n },\n // Note: Database.Service is provided inside the handler from space.db, not at the\n // operation level — the runtime can't fulfill it without a space context.\n services: [Capability.Service],\n input: Schema.Struct({\n channel: Type.getSchema(Channel.Channel),\n sender: Actor.Actor,\n text: Schema.String,\n }),\n output: Schema.Void,\n});\n\n/**\n * What a backend reports about a message it posted. `properties` are stamped on the copy a caller\n * records locally, so a mirror of that record (EDGE's Discord bot) can tell it was already posted.\n */\nexport const SendReceipt = Schema.Struct({\n messageIds: Schema.optional(Schema.Array(Schema.String).annotate({ description: 'Backend ids of the posts.' })),\n properties: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n});\n\nexport interface SendReceipt extends Schema.Schema.Type<typeof SendReceipt> {}\n\n/** Whether a backend's connection (a bot gateway, an IRC socket) is up. */\nexport const ConnectionStatus = Schema.Struct({\n running: Schema.Boolean,\n /** Backend-specific state name, e.g. a gateway's `connecting` or `ready`. */\n state: Schema.optional(Schema.String),\n detail: Schema.optional(Schema.String.annotate({ description: 'A short human-readable summary.' })),\n error: Schema.optional(Schema.String.annotate({ description: 'Why the connection last failed.' })),\n});\n\nexport interface ConnectionStatus extends Schema.Schema.Type<typeof ConnectionStatus> {}\n\n/** Sends text to a channel, or to a thread inside it, through the channel's backend. */\nexport const SendToChannel = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.sendToChannel'),\n name: 'Send to channel',\n description: \"Sends a message to a channel, or to a thread inside it, through the channel's backend.\",\n icon: 'ph--paper-plane-tilt--regular',\n },\n services: [Database.Service, Capability.Service],\n input: Schema.Struct({\n channel: Ref.Ref(Channel.Channel).annotate({ description: 'The channel to send to.' }),\n thread: Schema.optional(\n Schema.String.annotate({ description: 'A backend-scoped thread id (a Discord thread or DM channel id).' }),\n ),\n text: Schema.String.annotate({ description: 'The message.' }),\n }),\n output: Schema.Struct({\n delivered: Schema.Boolean,\n ...SendReceipt.fields,\n reason: Schema.optional(Schema.String.annotate({ description: 'Why the message was not delivered.' })),\n }),\n});\n\n/** Opens (or finds) a direct conversation with a person through the channel's account. */\nexport const OpenDirect = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.openDirect'),\n name: 'Open direct conversation',\n description:\n \"Opens a direct conversation (a DM) with a person through the channel's account; returns its thread id.\",\n icon: 'ph--user-circle--regular',\n },\n services: [Database.Service, Capability.Service],\n input: Schema.Struct({\n channel: Ref.Ref(Channel.Channel).annotate({ description: 'The channel whose account sends the direct message.' }),\n person: Ref.Ref(Person.Person).annotate({ description: 'The person to reach.' }),\n }),\n output: Schema.Struct({\n thread: Schema.optional(\n Schema.String.annotate({ description: 'The direct thread id; pass it to sendToChannel as `thread`.' }),\n ),\n reason: Schema.optional(Schema.String.annotate({ description: 'Why the person cannot be reached directly.' })),\n }),\n});\n\n/** Starts the channel's connection (or reconfigures a running one). */\nexport const ConnectChannel = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.connectChannel'),\n name: 'Connect channel',\n description: \"Starts the channel backend's connection, e.g. a bot gateway.\",\n icon: 'ph--play--regular',\n },\n services: [Database.Service, Capability.Service],\n input: Schema.Struct({\n channel: Ref.Ref(Channel.Channel).annotate({ description: 'The channel to connect.' }),\n }),\n output: Schema.Struct({ status: ConnectionStatus }),\n});\n\n/** Stops the channel's connection. */\nexport const DisconnectChannel = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.disconnectChannel'),\n name: 'Disconnect channel',\n description: \"Stops the channel backend's connection.\",\n icon: 'ph--stop--regular',\n },\n services: [Database.Service, Capability.Service],\n input: Schema.Struct({\n channel: Ref.Ref(Channel.Channel).annotate({ description: 'The channel to disconnect.' }),\n }),\n output: Schema.Struct({ status: ConnectionStatus }),\n});\n\n/** Reports the channel's connection status. */\nexport const GetChannelStatus = Operation.make({\n meta: {\n key: DXN.make('org.dxos.operation.thread.getChannelStatus'),\n name: 'Get channel status',\n description: \"Reports whether the channel backend's connection is up.\",\n icon: 'ph--pulse--regular',\n },\n services: [Database.Service, Capability.Service],\n input: Schema.Struct({\n channel: Ref.Ref(Channel.Channel).annotate({ description: 'The channel to report on.' }),\n }),\n output: Schema.Struct({ status: ConnectionStatus }),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAaA,IAAa,gBAAgB,UAAU,KAAK;CAC1C,MAAM;EACJ,KAAK,IAAI,KAAK,yCAAyC;EACvD,MAAM;EACN,MAAM;CACR;CACA,UAAU,CAAC,WAAW,OAAO;CAC7B,OAAO,OAAO,OAAO;EACnB,SAAS,IAAI;EACb,MAAM,OAAO,SAAS,OAAO,MAAM;;EAEnC,MAAM,OAAO,SAAS,OAAO,MAAM;;EAEnC,SAAS,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,GAAG,CAAC;CACnE,CAAC;CACD,QAAQ,OAAO,OAAO,EACpB,QAAQ,KAAK,UAAU,QAAQ,OAAO,EACxC,CAAC;AACH,CAAC;AAED,IAAa,uBAAuB,UAAU,KAAK;CACjD,MAAM;EACJ,KAAK,IAAI,KAAK,gDAAgD;EAC9D,MAAM;EACN,MAAM;CACR;CAGA,UAAU,CAAC,WAAW,OAAO;CAC7B,OAAO,OAAO,OAAO;EACnB,SAAS,KAAK,UAAU,QAAQ,OAAO;EACvC,QAAQ,MAAM;EACd,MAAM,OAAO;CACf,CAAC;CACD,QAAQ,OAAO;AACjB,CAAC;;;;;AAMD,IAAa,cAAc,OAAO,OAAO;CACvC,YAAY,OAAO,SAAS,OAAO,MAAM,OAAO,MAAM,CAAC,CAAC,SAAS,EAAE,aAAa,4BAA4B,CAAC,CAAC;CAC9G,YAAY,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;AAC1E,CAAC;;AAKD,IAAa,mBAAmB,OAAO,OAAO;CAC5C,SAAS,OAAO;;CAEhB,OAAO,OAAO,SAAS,OAAO,MAAM;CACpC,QAAQ,OAAO,SAAS,OAAO,OAAO,SAAS,EAAE,aAAa,kCAAkC,CAAC,CAAC;CAClG,OAAO,OAAO,SAAS,OAAO,OAAO,SAAS,EAAE,aAAa,kCAAkC,CAAC,CAAC;AACnG,CAAC;;AAKD,IAAa,gBAAgB,UAAU,KAAK;CAC1C,MAAM;EACJ,KAAK,IAAI,KAAK,yCAAyC;EACvD,MAAM;EACN,aAAa;EACb,MAAM;CACR;CACA,UAAU,CAAC,SAAS,SAAS,WAAW,OAAO;CAC/C,OAAO,OAAO,OAAO;EACnB,SAAS,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,0BAA0B,CAAC;EACrF,QAAQ,OAAO,SACb,OAAO,OAAO,SAAS,EAAE,aAAa,kEAAkE,CAAC,CAC3G;EACA,MAAM,OAAO,OAAO,SAAS,EAAE,aAAa,eAAe,CAAC;CAC9D,CAAC;CACD,QAAQ,OAAO,OAAO;EACpB,WAAW,OAAO;EAClB,GAAG,YAAY;EACf,QAAQ,OAAO,SAAS,OAAO,OAAO,SAAS,EAAE,aAAa,qCAAqC,CAAC,CAAC;CACvG,CAAC;AACH,CAAC;;AAGD,IAAa,aAAa,UAAU,KAAK;CACvC,MAAM;EACJ,KAAK,IAAI,KAAK,sCAAsC;EACpD,MAAM;EACN,aACE;EACF,MAAM;CACR;CACA,UAAU,CAAC,SAAS,SAAS,WAAW,OAAO;CAC/C,OAAO,OAAO,OAAO;EACnB,SAAS,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,sDAAsD,CAAC;EACjH,QAAQ,IAAI,IAAI,OAAO,MAAM,CAAC,CAAC,SAAS,EAAE,aAAa,uBAAuB,CAAC;CACjF,CAAC;CACD,QAAQ,OAAO,OAAO;EACpB,QAAQ,OAAO,SACb,OAAO,OAAO,SAAS,EAAE,aAAa,8DAA8D,CAAC,CACvG;EACA,QAAQ,OAAO,SAAS,OAAO,OAAO,SAAS,EAAE,aAAa,6CAA6C,CAAC,CAAC;CAC/G,CAAC;AACH,CAAC;;AAGD,IAAa,iBAAiB,UAAU,KAAK;CAC3C,MAAM;EACJ,KAAK,IAAI,KAAK,0CAA0C;EACxD,MAAM;EACN,aAAa;EACb,MAAM;CACR;CACA,UAAU,CAAC,SAAS,SAAS,WAAW,OAAO;CAC/C,OAAO,OAAO,OAAO,EACnB,SAAS,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,0BAA0B,CAAC,EACvF,CAAC;CACD,QAAQ,OAAO,OAAO,EAAE,QAAQ,iBAAiB,CAAC;AACpD,CAAC;;AAGD,IAAa,oBAAoB,UAAU,KAAK;CAC9C,MAAM;EACJ,KAAK,IAAI,KAAK,6CAA6C;EAC3D,MAAM;EACN,aAAa;EACb,MAAM;CACR;CACA,UAAU,CAAC,SAAS,SAAS,WAAW,OAAO;CAC/C,OAAO,OAAO,OAAO,EACnB,SAAS,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,6BAA6B,CAAC,EAC1F,CAAC;CACD,QAAQ,OAAO,OAAO,EAAE,QAAQ,iBAAiB,CAAC;AACpD,CAAC;;AAGD,IAAa,mBAAmB,UAAU,KAAK;CAC7C,MAAM;EACJ,KAAK,IAAI,KAAK,4CAA4C;EAC1D,MAAM;EACN,aAAa;EACb,MAAM;CACR;CACA,UAAU,CAAC,SAAS,SAAS,WAAW,OAAO;CAC/C,OAAO,OAAO,OAAO,EACnB,SAAS,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,4BAA4B,CAAC,EACzF,CAAC;CACD,QAAQ,OAAO,OAAO,EAAE,QAAQ,iBAAiB,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { ThreadOperation } from "#types";
|
|
3
|
+
import * as Operation from "@dxos/compute/Operation";
|
|
4
|
+
import * as OperationHandlerSet from "@dxos/compute/OperationHandlerSet";
|
|
5
|
+
//#region src/operations/ThreadOperationHandlerSet.ts
|
|
6
|
+
var ThreadOperationHandlerSet_exports = /* @__PURE__ */ __exportAll({ handlers: () => handlers });
|
|
7
|
+
var handlers = OperationHandlerSet.lazy([
|
|
8
|
+
ThreadOperation.AppendChannelMessage.pipe(Operation.lazyHandler(() => import("./chunk-append-channel-message.mjs"))),
|
|
9
|
+
ThreadOperation.CreateChannel.pipe(Operation.lazyHandler(() => import("./chunk-create-channel.mjs"))),
|
|
10
|
+
ThreadOperation.SendToChannel.pipe(Operation.lazyHandler(() => import("./chunk-send-to-channel.mjs"))),
|
|
11
|
+
ThreadOperation.OpenDirect.pipe(Operation.lazyHandler(() => import("./chunk-open-direct.mjs"))),
|
|
12
|
+
ThreadOperation.ConnectChannel.pipe(Operation.lazyHandler(() => import("./chunk-connect-channel.mjs"))),
|
|
13
|
+
ThreadOperation.DisconnectChannel.pipe(Operation.lazyHandler(() => import("./chunk-disconnect-channel.mjs"))),
|
|
14
|
+
ThreadOperation.GetChannelStatus.pipe(Operation.lazyHandler(() => import("./chunk-get-channel-status.mjs")))
|
|
15
|
+
]);
|
|
16
|
+
//#endregion
|
|
17
|
+
export { handlers, ThreadOperationHandlerSet_exports as t };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=ThreadOperationHandlerSet.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadOperationHandlerSet.mjs","names":[],"sources":["../../src/operations/ThreadOperationHandlerSet.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { ThreadOperation } from '#types';\n\nexport const handlers = OperationHandlerSet.lazy([\n ThreadOperation.AppendChannelMessage.pipe(Operation.lazyHandler(() => import('./append-channel-message.ts'))),\n ThreadOperation.CreateChannel.pipe(Operation.lazyHandler(() => import('./create-channel.ts'))),\n ThreadOperation.SendToChannel.pipe(Operation.lazyHandler(() => import('./send-to-channel.ts'))),\n ThreadOperation.OpenDirect.pipe(Operation.lazyHandler(() => import('./open-direct.ts'))),\n ThreadOperation.ConnectChannel.pipe(Operation.lazyHandler(() => import('./connect-channel.ts'))),\n ThreadOperation.DisconnectChannel.pipe(Operation.lazyHandler(() => import('./disconnect-channel.ts'))),\n ThreadOperation.GetChannelStatus.pipe(Operation.lazyHandler(() => import('./get-channel-status.ts'))),\n]);\n"],"mappings":";;;;;;AAWA,IAAa,WAAW,oBAAoB,KAAK;CAC/C,gBAAgB,qBAAqB,KAAK,UAAU,kBAAkB,OAAO,qCAA8B,CAAC;CAC5G,gBAAgB,cAAc,KAAK,UAAU,kBAAkB,OAAO,6BAAsB,CAAC;CAC7F,gBAAgB,cAAc,KAAK,UAAU,kBAAkB,OAAO,8BAAuB,CAAC;CAC9F,gBAAgB,WAAW,KAAK,UAAU,kBAAkB,OAAO,0BAAmB,CAAC;CACvF,gBAAgB,eAAe,KAAK,UAAU,kBAAkB,OAAO,8BAAuB,CAAC;CAC/F,gBAAgB,kBAAkB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;CACrG,gBAAgB,iBAAiB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;AACtG,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
|
|
3
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
4
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
5
|
+
import { translations } from "@dxos/react-ui-thread/translations";
|
|
6
|
+
import { translations as translations$1 } from "#translations";
|
|
7
|
+
import { ThreadCapabilities, ThreadEvents } from "#types";
|
|
8
|
+
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
9
|
+
import { meta } from "#meta";
|
|
10
|
+
//#region src/capabilities/gen/browser.ts
|
|
11
|
+
var AppGraphBuilder = AppCapability.appGraphBuilder(() => import("./chunk-app-graph-builder.mjs"));
|
|
12
|
+
var ChannelBackendFeed = Capability.lazyModule("ChannelBackendFeed", {
|
|
13
|
+
provides: [ThreadCapabilities.ChannelBackend],
|
|
14
|
+
activatesOn: ThreadEvents.Start,
|
|
15
|
+
environments: [
|
|
16
|
+
"browser",
|
|
17
|
+
"node",
|
|
18
|
+
"tauri",
|
|
19
|
+
"workerd"
|
|
20
|
+
]
|
|
21
|
+
}, () => import("./chunk-channel-backend-feed.mjs"));
|
|
22
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"), { environments: ["browser", "tauri"] });
|
|
23
|
+
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
24
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
25
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
26
|
+
var Translations = AppCapability.translations([...translations$1, ...translations]);
|
|
27
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
28
|
+
pluginId: meta.profile.key,
|
|
29
|
+
path: "PLUGIN.mdl",
|
|
30
|
+
content: PLUGIN_default,
|
|
31
|
+
mimeType: "application/x-mdl"
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export { AppGraphBuilder, ChannelBackendFeed, CreateObject, OperationHandler, PluginAsset, ReactSurface, Schema, Translations };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=capabilities.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.browser.mjs","names":[],"sources":["../../src/capabilities/gen/browser.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'browser' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('../app-graph-builder.ts'));\n\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['browser', 'node', 'tauri', 'workerd'],\n },\n () => import('../channel-backend-feed.ts'),\n);\n\n// `CreateObjectEntry` carries a `customPanel` React component alongside the object factory, so it\n// cannot load without React — browser only.\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'), {\n environments: ['browser', 'tauri'],\n});\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n"],"mappings":";;;;;;;;;;AAqBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,gCAA0B;AAEpG,IAAa,qBAAqB,WAAW,WAC3C,sBACA;CACE,UAAU,CAAC,mBAAmB,cAAc;CAC5C,aAAa,aAAa;CAC1B,cAAc;EAAC;EAAW;EAAQ;EAAS;CAAS;AACtD,SACM,OAAO,mCACf;AAIA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,8BAAwB,EAC5F,cAAc,CAAC,WAAW,OAAO,EACnC,CAAC;AAED,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,CAAC,GAAG,gBAAc,GAAG,YAAkB,CAAC;AAE/F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
1
2
|
import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
|
|
2
3
|
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
4
|
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
@@ -6,17 +7,19 @@ import { translations as translations$1 } from "#translations";
|
|
|
6
7
|
import { ThreadCapabilities, ThreadEvents } from "#types";
|
|
7
8
|
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
8
9
|
import { meta } from "#meta";
|
|
9
|
-
//#region PLUGIN.mdl?raw
|
|
10
|
-
var PLUGIN_default = "---\nid: org.dxos.plugin.thread\nname: ThreadPlugin\nversion: 0.1.0\n---\n\nThreadPlugin provides chat: channels backed by an ECHO feed and free-standing message threads.\nIt renders the channel article + companion surfaces and a thread surface, and contributes the\noperations that create a channel and append messages. Shared message/thread UI comes from\n`@dxos/react-ui-thread`, and the `Channel`/`Message`/`Thread` schema comes from `@dxos/types`.\nDocument comments and the comment-thread AI agent live in `@dxos/plugin-comments`.\n\n## Extensions\n\nThe following extension dialects are used in this document.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype Channel\n desc: |\n A chat channel. Defined in @dxos/types. Carries an optional `feed` Ref whose\n queue holds the channel's Message objects in order.\n```\n\n## Operations\n\n```mdl\nop OnCreateSpace\n key: org.dxos.plugin.thread.operation.onCreateSpace\n desc: On space creation, create a default \"General\" channel in the root collection.\n```\n\n```mdl\nop CreateChannel\n key: org.dxos.operation.thread.createChannel\n desc: Create a new Channel in the given space.\n in:\n spaceId: SpaceId\n name?: String\n out:\n object: Channel\n```\n\n```mdl\nop AppendChannelMessage\n key: org.dxos.operation.thread.appendChannelMessage\n desc: Append a Message authored by `sender` to the channel's feed.\n in:\n channel: Channel\n sender: Actor\n text: String\n```\n\n## Features\n\n```mdl\nfeat F-1: Channel chat\n req F-1.1: A Channel article MUST render its feed messages newest-last with a\n pinned composer; sending invokes AppendChannelMessage.\n req F-1.2: Externally-synced channels (those carrying foreign-key Obj.Meta) MUST\n render read-only — the composer is suppressed.\n```\n\n```mdl\nfeat F-2: Thread chat\n req F-2.1: A Thread article MUST render the thread's messages and append new\n messages by pushing onto `thread.messages`.\n```\n";
|
|
11
|
-
//#endregion
|
|
12
10
|
//#region src/capabilities/index.ts
|
|
13
11
|
var AppGraphBuilder = AppCapability.appGraphBuilder(() => import("./chunk-app-graph-builder.mjs"));
|
|
14
12
|
var ChannelBackendFeed = Capability.lazyModule("ChannelBackendFeed", {
|
|
15
13
|
provides: [ThreadCapabilities.ChannelBackend],
|
|
16
14
|
activatesOn: ThreadEvents.Start,
|
|
17
|
-
environments: [
|
|
15
|
+
environments: [
|
|
16
|
+
"browser",
|
|
17
|
+
"node",
|
|
18
|
+
"tauri",
|
|
19
|
+
"workerd"
|
|
20
|
+
]
|
|
18
21
|
}, () => import("./chunk-channel-backend-feed.mjs"));
|
|
19
|
-
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"), { environments: [] });
|
|
22
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"), { environments: ["browser", "tauri"] });
|
|
20
23
|
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
21
24
|
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
22
25
|
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('./app-graph-builder'));\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['node', 'workerd'],\n },\n () => import('./channel-backend-feed'),\n);\n// `CreateObjectEntry` carries a `customPanel` React component alongside the object factory, so it\n// cannot load without React — browser only.\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object'), {\n environments: [],\n});\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema'));\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('./app-graph-builder.ts'));\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['browser', 'node', 'tauri', 'workerd'],\n },\n () => import('./channel-backend-feed.ts'),\n);\n// `CreateObjectEntry` carries a `customPanel` React component alongside the object factory, so it\n// cannot load without React — browser only.\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object.ts'), {\n environments: ['browser', 'tauri'],\n});\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema.ts'));\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n"],"mappings":";;;;;;;;;;AAoBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,gCAAyB;AACnG,IAAa,qBAAqB,WAAW,WAC3C,sBACA;CACE,UAAU,CAAC,mBAAmB,cAAc;CAC5C,aAAa,aAAa;CAC1B,cAAc;EAAC;EAAW;EAAQ;EAAS;CAAS;AACtD,SACM,OAAO,mCACf;AAGA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,8BAAuB,EAC3F,cAAc,CAAC,WAAW,OAAO,EACnC,CAAC;AACD,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA2B,EACrG,aAAa,iBAAiB,KAChC,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAuB,EACpF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AACD,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAc;AACtE,IAAa,eAAe,cAAc,aAAa,CAAC,GAAG,gBAAc,GAAG,YAAkB,CAAC;AAC/F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC"}
|
|
@@ -9,7 +9,12 @@ var AppGraphBuilder = AppCapability.appGraphBuilder(() => import("./chunk-app-gr
|
|
|
9
9
|
var ChannelBackendFeed = Capability.lazyModule("ChannelBackendFeed", {
|
|
10
10
|
provides: [ThreadCapabilities.ChannelBackend],
|
|
11
11
|
activatesOn: ThreadEvents.Start,
|
|
12
|
-
environments: [
|
|
12
|
+
environments: [
|
|
13
|
+
"browser",
|
|
14
|
+
"node",
|
|
15
|
+
"tauri",
|
|
16
|
+
"workerd"
|
|
17
|
+
]
|
|
13
18
|
}, () => import("./chunk-channel-backend-feed.mjs"));
|
|
14
19
|
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
15
20
|
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('../app-graph-builder'));\n\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['node', 'workerd'],\n },\n () => import('../channel-backend-feed'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema'));\n\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\n\nexport const CreateObject = undefined;\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;AAiBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('../app-graph-builder.ts'));\n\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['browser', 'node', 'tauri', 'workerd'],\n },\n () => import('../channel-backend-feed.ts'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\n\nexport const CreateObject = undefined;\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;AAiBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,gCAA0B;AAEpG,IAAa,qBAAqB,WAAW,WAC3C,sBACA;CACE,UAAU,CAAC,mBAAmB,cAAc;CAC5C,aAAa,aAAa;CAC1B,cAAc;EAAC;EAAW;EAAQ;EAAS;CAAS;AACtD,SACM,OAAO,mCACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,CAAC,GAAG,gBAAc,GAAG,YAAkB,CAAC;AAE/F,IAAa,eAAe,KAAA;AAC5B,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
|
|
3
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
4
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
5
|
+
import { translations } from "@dxos/react-ui-thread/translations";
|
|
6
|
+
import { translations as translations$1 } from "#translations";
|
|
7
|
+
import { ThreadCapabilities, ThreadEvents } from "#types";
|
|
8
|
+
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
9
|
+
import { meta } from "#meta";
|
|
10
|
+
//#region src/capabilities/gen/tauri.ts
|
|
11
|
+
var AppGraphBuilder = AppCapability.appGraphBuilder(() => import("./chunk-app-graph-builder.mjs"));
|
|
12
|
+
var ChannelBackendFeed = Capability.lazyModule("ChannelBackendFeed", {
|
|
13
|
+
provides: [ThreadCapabilities.ChannelBackend],
|
|
14
|
+
activatesOn: ThreadEvents.Start,
|
|
15
|
+
environments: [
|
|
16
|
+
"browser",
|
|
17
|
+
"node",
|
|
18
|
+
"tauri",
|
|
19
|
+
"workerd"
|
|
20
|
+
]
|
|
21
|
+
}, () => import("./chunk-channel-backend-feed.mjs"));
|
|
22
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"), { environments: ["browser", "tauri"] });
|
|
23
|
+
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
24
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
25
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
26
|
+
var Translations = AppCapability.translations([...translations$1, ...translations]);
|
|
27
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
28
|
+
pluginId: meta.profile.key,
|
|
29
|
+
path: "PLUGIN.mdl",
|
|
30
|
+
content: PLUGIN_default,
|
|
31
|
+
mimeType: "application/x-mdl"
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export { AppGraphBuilder, ChannelBackendFeed, CreateObject, OperationHandler, PluginAsset, ReactSurface, Schema, Translations };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=capabilities.tauri.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.tauri.mjs","names":[],"sources":["../../src/capabilities/gen/tauri.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'tauri' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\nimport { translations as threadTranslations } from '@dxos/react-ui-thread/translations';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { ThreadCapabilities, ThreadEvents } from '#types';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\n// The graph builder reads the call manager OPTIONALLY (reactive atom with an absence guard),\n// so no spec-level require: a hard cross-plugin require would fail this plugin whenever\n// plugin-calls is disabled. Cross-feature requires are only valid with a plugin-level dependsOn.\nexport const AppGraphBuilder = AppCapability.appGraphBuilder(() => import('../app-graph-builder.ts'));\n\nexport const ChannelBackendFeed = Capability.lazyModule(\n 'ChannelBackendFeed',\n {\n provides: [ThreadCapabilities.ChannelBackend],\n activatesOn: ThreadEvents.Start,\n environments: ['browser', 'node', 'tauri', 'workerd'],\n },\n () => import('../channel-backend-feed.ts'),\n);\n\n// `CreateObjectEntry` carries a `customPanel` React component alongside the object factory, so it\n// cannot load without React — browser only.\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'), {\n environments: ['browser', 'tauri'],\n});\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations([...translations, ...threadTranslations]);\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n"],"mappings":";;;;;;;;;;AAqBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,gCAA0B;AAEpG,IAAa,qBAAqB,WAAW,WAC3C,sBACA;CACE,UAAU,CAAC,mBAAmB,cAAc;CAC5C,aAAa,aAAa;CAC1B,cAAc;EAAC;EAAW;EAAQ;EAAS;CAAS;AACtD,SACM,OAAO,mCACf;AAIA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,8BAAwB,EAC5F,cAAc,CAAC,WAAW,OAAO,EACnC,CAAC;AAED,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,CAAC,GAAG,gBAAc,GAAG,YAAkB,CAAC;AAE/F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC"}
|
|
@@ -9,7 +9,12 @@ var AppGraphBuilder = AppCapability.appGraphBuilder(() => import("./chunk-app-gr
|
|
|
9
9
|
var ChannelBackendFeed = Capability.lazyModule("ChannelBackendFeed", {
|
|
10
10
|
provides: [ThreadCapabilities.ChannelBackend],
|
|
11
11
|
activatesOn: ThreadEvents.Start,
|
|
12
|
-
environments: [
|
|
12
|
+
environments: [
|
|
13
|
+
"browser",
|
|
14
|
+
"node",
|
|
15
|
+
"tauri",
|
|
16
|
+
"workerd"
|
|
17
|
+
]
|
|
13
18
|
}, () => import("./chunk-channel-backend-feed.mjs"));
|
|
14
19
|
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
15
20
|
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|