@dxos/plugin-crx 0.0.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/LICENSE +105 -0
- package/PLUGIN.mdl +599 -0
- package/README.md +25 -0
- package/dist/lib/CrxCapabilities.mjs +21 -0
- package/dist/lib/CrxCapabilities.mjs.map +1 -0
- package/dist/lib/CrxEvents.mjs +15 -0
- package/dist/lib/CrxEvents.mjs.map +1 -0
- package/dist/lib/CrxOperation.mjs +50 -0
- package/dist/lib/CrxOperation.mjs.map +1 -0
- package/dist/lib/CrxPlugin.mjs +16 -0
- package/dist/lib/CrxPlugin.mjs.map +1 -0
- package/dist/lib/PageAction.mjs +35 -0
- package/dist/lib/PageAction.mjs.map +1 -0
- package/dist/lib/Settings.mjs +84 -0
- package/dist/lib/Settings.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +41 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/capabilities.node.mjs +32 -0
- package/dist/lib/capabilities.node.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs +32 -0
- package/dist/lib/capabilities.workerd.mjs.map +1 -0
- package/dist/lib/chunk-add-note-from-snapshot.mjs +15 -0
- package/dist/lib/chunk-add-note-from-snapshot.mjs.map +1 -0
- package/dist/lib/chunk-add-organization-from-snapshot.mjs +15 -0
- package/dist/lib/chunk-add-organization-from-snapshot.mjs.map +1 -0
- package/dist/lib/chunk-add-person-from-snapshot.mjs +15 -0
- package/dist/lib/chunk-add-person-from-snapshot.mjs.map +1 -0
- package/dist/lib/chunk-install-page-actions.mjs +284 -0
- package/dist/lib/chunk-install-page-actions.mjs.map +1 -0
- package/dist/lib/chunk-mapping.mjs +81 -0
- package/dist/lib/chunk-mapping.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +12 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-page-action-provider.mjs +41 -0
- package/dist/lib/chunk-page-action-provider.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +18 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
- package/dist/lib/chunk-settings.mjs +28 -0
- package/dist/lib/chunk-settings.mjs.map +1 -0
- package/dist/lib/containers.mjs +80 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/meta.mjs +34 -0
- package/dist/lib/meta.mjs.map +1 -0
- package/dist/lib/operations.mjs +13 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/translations.mjs +22 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +6 -0
- package/dist/lib/util.mjs +63 -0
- package/dist/lib/util.mjs.map +1 -0
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/CrxPlugin.d.ts +37 -0
- package/dist/types/src/CrxPlugin.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/node.d.ts +9 -0
- package/dist/types/src/capabilities/gen/node.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts +9 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +9 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/install-page-actions.d.ts +5 -0
- package/dist/types/src/capabilities/install-page-actions.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +5 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/page-action-provider.d.ts +5 -0
- package/dist/types/src/capabilities/page-action-provider.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +10 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/containers/CrxSettings/CrxSettings.d.ts +10 -0
- package/dist/types/src/containers/CrxSettings/CrxSettings.d.ts.map +1 -0
- package/dist/types/src/containers/CrxSettings/CrxSettings.stories.d.ts +25 -0
- package/dist/types/src/containers/CrxSettings/CrxSettings.stories.d.ts.map +1 -0
- package/dist/types/src/containers/CrxSettings/index.d.ts +2 -0
- package/dist/types/src/containers/CrxSettings/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +2 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/mapping.d.ts +24 -0
- package/dist/types/src/mapping.d.ts.map +1 -0
- package/dist/types/src/mapping.test.d.ts +2 -0
- package/dist/types/src/mapping.test.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +33 -0
- package/dist/types/src/meta.d.ts.map +1 -0
- package/dist/types/src/operations/add-note-from-snapshot.d.ts +5 -0
- package/dist/types/src/operations/add-note-from-snapshot.d.ts.map +1 -0
- package/dist/types/src/operations/add-organization-from-snapshot.d.ts +5 -0
- package/dist/types/src/operations/add-organization-from-snapshot.d.ts.map +1 -0
- package/dist/types/src/operations/add-person-from-snapshot.d.ts +5 -0
- package/dist/types/src/operations/add-person-from-snapshot.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/page-actions.d.ts +39 -0
- package/dist/types/src/page-actions.d.ts.map +1 -0
- package/dist/types/src/page-actions.test.d.ts +2 -0
- package/dist/types/src/page-actions.test.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/stories/Testbench.stories.d.ts +8 -0
- package/dist/types/src/stories/Testbench.stories.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +22 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/types/CrxCapabilities.d.ts +12 -0
- package/dist/types/src/types/CrxCapabilities.d.ts.map +1 -0
- package/dist/types/src/types/CrxEvents.d.ts +8 -0
- package/dist/types/src/types/CrxEvents.d.ts.map +1 -0
- package/dist/types/src/types/CrxOperation.d.ts +108 -0
- package/dist/types/src/types/CrxOperation.d.ts.map +1 -0
- package/dist/types/src/types/PageAction.d.ts +153 -0
- package/dist/types/src/types/PageAction.d.ts.map +1 -0
- package/dist/types/src/types/Settings.d.ts +25 -0
- package/dist/types/src/types/Settings.d.ts.map +1 -0
- package/dist/types/src/types/Settings.test.d.ts +2 -0
- package/dist/types/src/types/Settings.test.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +6 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/pingExtension.d.ts +15 -0
- package/dist/types/src/util/pingExtension.d.ts.map +1 -0
- package/dist/types/src/util/pingExtension.test.d.ts +2 -0
- package/dist/types/src/util/pingExtension.test.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dx.config.ts +32 -0
- package/package.json +162 -0
- package/src/CrxPlugin.ts +15 -0
- package/src/capabilities/gen/node.ts +43 -0
- package/src/capabilities/gen/workerd.ts +43 -0
- package/src/capabilities/index.ts +47 -0
- package/src/capabilities/install-page-actions.ts +64 -0
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/page-action-provider.ts +47 -0
- package/src/capabilities/react-surface.ts +26 -0
- package/src/capabilities/settings.ts +36 -0
- package/src/containers/CrxSettings/CrxSettings.stories.tsx +99 -0
- package/src/containers/CrxSettings/CrxSettings.tsx +100 -0
- package/src/containers/CrxSettings/index.ts +5 -0
- package/src/containers/index.ts +5 -0
- package/src/index.ts +7 -0
- package/src/mapping.test.ts +87 -0
- package/src/mapping.ts +101 -0
- package/src/meta.ts +9 -0
- package/src/operations/add-note-from-snapshot.ts +24 -0
- package/src/operations/add-organization-from-snapshot.ts +29 -0
- package/src/operations/add-person-from-snapshot.ts +29 -0
- package/src/operations/index.ts +16 -0
- package/src/page-actions.test.ts +164 -0
- package/src/page-actions.ts +171 -0
- package/src/plugin.tsx +29 -0
- package/src/stories/Testbench.stories.tsx +45 -0
- package/src/translations.ts +31 -0
- package/src/types/CrxCapabilities.ts +26 -0
- package/src/types/CrxEvents.ts +16 -0
- package/src/types/CrxOperation.ts +54 -0
- package/src/types/PageAction.ts +57 -0
- package/src/types/Settings.test.ts +30 -0
- package/src/types/Settings.ts +101 -0
- package/src/types/index.ts +9 -0
- package/src/util/index.ts +5 -0
- package/src/util/pingExtension.test.ts +69 -0
- package/src/util/pingExtension.ts +83 -0
- package/src/vite-env.d.ts +10 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import { CrxCapabilities, PageAction, Settings } from "#types";
|
|
4
|
+
import { meta } from "#meta";
|
|
5
|
+
import * as Schema from "effect/Schema";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as LayoutOperation from "@dxos/app-toolkit/LayoutOperation";
|
|
8
|
+
import * as NavigationOperation from "@dxos/app-toolkit/NavigationOperation";
|
|
9
|
+
import { EID, EntityId } from "@dxos/keys";
|
|
10
|
+
import { log } from "@dxos/log";
|
|
11
|
+
import * as Result from "effect/Result";
|
|
12
|
+
import * as AppSpace from "@dxos/app-toolkit/AppSpace";
|
|
13
|
+
import * as ClientCapabilities from "@dxos/plugin-client/ClientCapabilities";
|
|
14
|
+
//#region src/page-actions.ts
|
|
15
|
+
var __dxlog_file$1 = "/Users/dmaretskyi/Code/dxos/dxos/.claude/worktrees/publish-plugin-github/packages/plugins/plugin-crx/src/page-actions.ts";
|
|
16
|
+
/**
|
|
17
|
+
* Answer a registry-list request with the currently contributed actions as
|
|
18
|
+
* serializable descriptors.
|
|
19
|
+
*/
|
|
20
|
+
var handleListEvent = (detail, getActions) => {
|
|
21
|
+
const decoded = Schema.decodeUnknownResult(PageAction.ListRequest)(detail);
|
|
22
|
+
if (Result.isFailure(decoded)) {
|
|
23
|
+
log.info("rejected invalid page-actions list request", void 0, {
|
|
24
|
+
"~LogMeta": "~LogMeta",
|
|
25
|
+
F: __dxlog_file$1,
|
|
26
|
+
L: 40,
|
|
27
|
+
S: void 0
|
|
28
|
+
});
|
|
29
|
+
const envelope = Schema.decodeUnknownResult(PageAction.Envelope)(detail);
|
|
30
|
+
return {
|
|
31
|
+
version: 1,
|
|
32
|
+
id: Result.isSuccess(envelope) ? envelope.success.id ?? "" : "",
|
|
33
|
+
ok: false,
|
|
34
|
+
error: "invalidPayload"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
version: 1,
|
|
39
|
+
id: decoded.success.id,
|
|
40
|
+
ok: true,
|
|
41
|
+
actions: getActions().map(PageAction.toDescriptor)
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Handle a single invoke request. Two-pass decode (loose envelope, then
|
|
46
|
+
* strict payload) so newer versions yield `unsupportedVersion` rather than
|
|
47
|
+
* the generic `invalidPayload`.
|
|
48
|
+
*/
|
|
49
|
+
var handleInvokeEvent = async (detail, deps) => {
|
|
50
|
+
const envelope = Schema.decodeUnknownResult(PageAction.Envelope)(detail);
|
|
51
|
+
if (Result.isFailure(envelope)) {
|
|
52
|
+
log.info("rejected invalid page-action envelope", void 0, {
|
|
53
|
+
"~LogMeta": "~LogMeta",
|
|
54
|
+
F: __dxlog_file$1,
|
|
55
|
+
L: 62,
|
|
56
|
+
S: void 0
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
version: 1,
|
|
60
|
+
id: "",
|
|
61
|
+
ok: false,
|
|
62
|
+
error: "invalidPayload"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const envelopeId = envelope.success.id ?? "";
|
|
66
|
+
if (!Settings.withDefaults(deps.getSettings()).enabled) {
|
|
67
|
+
log.info("ignored page action: extension actions disabled in settings", void 0, {
|
|
68
|
+
"~LogMeta": "~LogMeta",
|
|
69
|
+
F: __dxlog_file$1,
|
|
70
|
+
L: 71,
|
|
71
|
+
S: void 0
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
version: 1,
|
|
75
|
+
id: envelopeId,
|
|
76
|
+
ok: false,
|
|
77
|
+
error: "disabled"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (envelope.success.version !== 1) {
|
|
81
|
+
log.info("rejected unsupported page-action version", { version: envelope.success.version }, {
|
|
82
|
+
"~LogMeta": "~LogMeta",
|
|
83
|
+
F: __dxlog_file$1,
|
|
84
|
+
L: 76,
|
|
85
|
+
S: void 0
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
version: 1,
|
|
89
|
+
id: envelopeId,
|
|
90
|
+
ok: false,
|
|
91
|
+
error: "unsupportedVersion"
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const decoded = Schema.decodeUnknownResult(PageAction.InvokeRequest)(detail);
|
|
95
|
+
if (Result.isFailure(decoded)) {
|
|
96
|
+
log.info("rejected invalid page-action payload", void 0, {
|
|
97
|
+
"~LogMeta": "~LogMeta",
|
|
98
|
+
F: __dxlog_file$1,
|
|
99
|
+
L: 82,
|
|
100
|
+
S: void 0
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
version: 1,
|
|
104
|
+
id: envelopeId,
|
|
105
|
+
ok: false,
|
|
106
|
+
error: "invalidPayload"
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const request = decoded.success;
|
|
110
|
+
const action = deps.getActions().find((candidate) => candidate.id === request.actionId);
|
|
111
|
+
if (!action) {
|
|
112
|
+
log.info("rejected unknown page action", { actionId: request.actionId }, {
|
|
113
|
+
"~LogMeta": "~LogMeta",
|
|
114
|
+
F: __dxlog_file$1,
|
|
115
|
+
L: 89,
|
|
116
|
+
S: void 0
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
version: 1,
|
|
120
|
+
id: request.id,
|
|
121
|
+
ok: false,
|
|
122
|
+
error: "unknownAction"
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const target = deps.getTarget();
|
|
126
|
+
if (!target) return {
|
|
127
|
+
version: 1,
|
|
128
|
+
id: request.id,
|
|
129
|
+
ok: false,
|
|
130
|
+
error: "noSpace"
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
const { data, error } = await deps.invoke(action.operation, {
|
|
134
|
+
snapshot: request.inputs,
|
|
135
|
+
target
|
|
136
|
+
});
|
|
137
|
+
if (error || !data) {
|
|
138
|
+
log.info("page-action operation failed", {
|
|
139
|
+
actionId: action.id,
|
|
140
|
+
error
|
|
141
|
+
}, {
|
|
142
|
+
"~LogMeta": "~LogMeta",
|
|
143
|
+
F: __dxlog_file$1,
|
|
144
|
+
L: 101,
|
|
145
|
+
S: void 0
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
version: 1,
|
|
149
|
+
id: request.id,
|
|
150
|
+
ok: false,
|
|
151
|
+
error: "operationFailed"
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
log.info("page action invoked", {
|
|
155
|
+
actionId: action.id,
|
|
156
|
+
objectId: data.id
|
|
157
|
+
}, {
|
|
158
|
+
"~LogMeta": "~LogMeta",
|
|
159
|
+
F: __dxlog_file$1,
|
|
160
|
+
L: 104,
|
|
161
|
+
S: void 0
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
version: 1,
|
|
165
|
+
id: request.id,
|
|
166
|
+
ok: true,
|
|
167
|
+
objectId: data.id
|
|
168
|
+
};
|
|
169
|
+
} catch (err) {
|
|
170
|
+
log.catch(err, void 0, {
|
|
171
|
+
"~LogMeta": "~LogMeta",
|
|
172
|
+
F: __dxlog_file$1,
|
|
173
|
+
L: 107,
|
|
174
|
+
S: void 0
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
version: 1,
|
|
178
|
+
id: request.id,
|
|
179
|
+
ok: false,
|
|
180
|
+
error: "operationFailed"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Attach the page-actions window event listeners. Returns a disposer.
|
|
186
|
+
* Actions are resolved per-event via `getAll` so late-activating plugins are
|
|
187
|
+
* always included.
|
|
188
|
+
*/
|
|
189
|
+
var installPageActionListeners = (capabilities, invoker, onResult) => {
|
|
190
|
+
const getActions = () => capabilities.getAll(CrxCapabilities.PageAction).flat();
|
|
191
|
+
const onList = (event) => {
|
|
192
|
+
const ack = handleListEvent(event.detail, getActions);
|
|
193
|
+
window.dispatchEvent(new CustomEvent(PageAction.LIST_ACK_EVENT, { detail: ack }));
|
|
194
|
+
};
|
|
195
|
+
const onInvoke = (event) => {
|
|
196
|
+
const detail = event.detail;
|
|
197
|
+
let target;
|
|
198
|
+
handleInvokeEvent(detail, {
|
|
199
|
+
getActions,
|
|
200
|
+
getSettings: () => capabilities.get(Capabilities.AtomRegistry).get(capabilities.get(CrxCapabilities.Settings)),
|
|
201
|
+
getTarget: () => {
|
|
202
|
+
const client = capabilities.get(ClientCapabilities.Client);
|
|
203
|
+
target = AppSpace.getActiveSpace(client, capabilities)?.db;
|
|
204
|
+
return target;
|
|
205
|
+
},
|
|
206
|
+
invoke: (operation, input) => invoker.invokePromise(operation, input)
|
|
207
|
+
}).catch((err) => {
|
|
208
|
+
log.catch(err, void 0, {
|
|
209
|
+
"~LogMeta": "~LogMeta",
|
|
210
|
+
F: __dxlog_file$1,
|
|
211
|
+
L: 145,
|
|
212
|
+
S: void 0
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
version: 1,
|
|
216
|
+
id: "",
|
|
217
|
+
ok: false,
|
|
218
|
+
error: "operationFailed"
|
|
219
|
+
};
|
|
220
|
+
}).then((ack) => {
|
|
221
|
+
window.dispatchEvent(new CustomEvent(PageAction.INVOKE_ACK_EVENT, { detail: ack }));
|
|
222
|
+
try {
|
|
223
|
+
const actionId = detail?.actionId;
|
|
224
|
+
onResult?.(ack, getActions().find((candidate) => candidate.id === actionId)?.label, target?.spaceId);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
log.catch(err, void 0, {
|
|
227
|
+
"~LogMeta": "~LogMeta",
|
|
228
|
+
F: __dxlog_file$1,
|
|
229
|
+
L: 154,
|
|
230
|
+
S: void 0
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
window.addEventListener(PageAction.LIST_EVENT, onList);
|
|
236
|
+
window.addEventListener(PageAction.INVOKE_EVENT, onInvoke);
|
|
237
|
+
window.dispatchEvent(new CustomEvent(PageAction.READY_EVENT));
|
|
238
|
+
return () => {
|
|
239
|
+
window.removeEventListener(PageAction.LIST_EVENT, onList);
|
|
240
|
+
window.removeEventListener(PageAction.INVOKE_EVENT, onInvoke);
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/capabilities/install-page-actions.ts
|
|
245
|
+
var __dxlog_file = "/Users/dmaretskyi/Code/dxos/dxos/.claude/worktrees/publish-plugin-github/packages/plugins/plugin-crx/src/capabilities/install-page-actions.ts";
|
|
246
|
+
var openObject = async (invoker, uri) => {
|
|
247
|
+
const { data } = await invoker.invokePromise(NavigationOperation.ResolveNavigationTargets, { query: { uri } });
|
|
248
|
+
const path = data?.targets[0]?.path;
|
|
249
|
+
if (path) await invoker.invokePromise(LayoutOperation.Open, { subject: [path] });
|
|
250
|
+
};
|
|
251
|
+
var install_page_actions_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
252
|
+
const capabilityManager = yield* Capability.Service;
|
|
253
|
+
const invoker = yield* Capabilities.OperationInvoker;
|
|
254
|
+
const registry = yield* Capabilities.AtomRegistry;
|
|
255
|
+
const settingsAtom = yield* CrxCapabilities.Settings;
|
|
256
|
+
installPageActionListeners(capabilityManager, invoker, (ack, _label, spaceId) => {
|
|
257
|
+
if (ack.ok) {
|
|
258
|
+
invoker.invokePromise(LayoutOperation.AddToast, {
|
|
259
|
+
id: `${meta.profile.key}.page-action-${ack.objectId ?? ack.id}`,
|
|
260
|
+
title: ["toast.page-action.success.title", { ns: meta.profile.key }]
|
|
261
|
+
});
|
|
262
|
+
const entityId = ack.objectId;
|
|
263
|
+
if (spaceId && entityId && EntityId.isValid(entityId) && Settings.withDefaults(registry.get(settingsAtom)).autoOpenAfterClip) openObject(invoker, EID.make({
|
|
264
|
+
spaceId,
|
|
265
|
+
entityId
|
|
266
|
+
}));
|
|
267
|
+
} else invoker.invokePromise(LayoutOperation.AddToast, {
|
|
268
|
+
id: `${meta.profile.key}.page-action-error-${Date.now()}`,
|
|
269
|
+
title: ["toast.page-action.error.title", { ns: meta.profile.key }],
|
|
270
|
+
description: [`toast.error.${ack.error}.message`, { ns: meta.profile.key }]
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
log.info("CRX page-actions bridge installed", void 0, {
|
|
274
|
+
"~LogMeta": "~LogMeta",
|
|
275
|
+
F: __dxlog_file,
|
|
276
|
+
L: 60,
|
|
277
|
+
S: this
|
|
278
|
+
});
|
|
279
|
+
return [];
|
|
280
|
+
}));
|
|
281
|
+
//#endregion
|
|
282
|
+
export { install_page_actions_default as default };
|
|
283
|
+
|
|
284
|
+
//# sourceMappingURL=chunk-install-page-actions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-install-page-actions.mjs","names":[],"sources":["../../src/page-actions.ts","../../src/capabilities/install-page-actions.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Result from 'effect/Result';\nimport * as Schema from 'effect/Schema';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport type * as CapabilityManager from '@dxos/app-framework/CapabilityManager';\nimport * as AppSpace from '@dxos/app-toolkit/AppSpace';\nimport { type Database } from '@dxos/echo';\nimport { type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\n\nimport { CrxCapabilities, PageAction, Settings } from '#types';\n\n/**\n * Dependencies for the invoke handler, injected so the handler can be\n * unit-tested without a capability manager (the capability module wires the\n * real implementations).\n */\nexport type InvokeDeps = {\n getActions: () => PageAction.PageAction[];\n getSettings: () => Settings.Settings;\n getTarget: () => Database.Database | undefined;\n invoke: (\n operation: PageAction.PageAction['operation'],\n input: unknown,\n ) => Promise<{ data?: { id?: string }; error?: unknown }>;\n};\n\n/**\n * Answer a registry-list request with the currently contributed actions as\n * serializable descriptors.\n */\nexport const handleListEvent = (detail: unknown, getActions: () => PageAction.PageAction[]): PageAction.ListAck => {\n const decoded = Schema.decodeUnknownResult(PageAction.ListRequest)(detail);\n if (Result.isFailure(decoded)) {\n log.info('rejected invalid page-actions list request');\n // Best-effort id echo so the extension can correlate the failure ack.\n const envelope = Schema.decodeUnknownResult(PageAction.Envelope)(detail);\n const id = Result.isSuccess(envelope) ? (envelope.success.id ?? '') : '';\n return { version: 1, id, ok: false, error: 'invalidPayload' };\n }\n return {\n version: 1,\n id: decoded.success.id,\n ok: true,\n actions: getActions().map(PageAction.toDescriptor),\n };\n};\n\n/**\n * Handle a single invoke request. Two-pass decode (loose envelope, then\n * strict payload) so newer versions yield `unsupportedVersion` rather than\n * the generic `invalidPayload`.\n */\nexport const handleInvokeEvent = async (detail: unknown, deps: InvokeDeps): Promise<PageAction.InvokeAck> => {\n const envelope = Schema.decodeUnknownResult(PageAction.Envelope)(detail);\n if (Result.isFailure(envelope)) {\n log.info('rejected invalid page-action envelope');\n return { version: 1, id: '', ok: false, error: 'invalidPayload' };\n }\n // Best-effort id echo so the extension can correlate failure acks.\n const envelopeId = envelope.success.id ?? '';\n\n // Master toggle: when off, the bridge acks (so the extension does not time\n // out) but ignores all extension-initiated actions.\n if (!Settings.withDefaults(deps.getSettings()).enabled) {\n log.info('ignored page action: extension actions disabled in settings');\n return { version: 1, id: envelopeId, ok: false, error: 'disabled' };\n }\n\n if (envelope.success.version !== 1) {\n log.info('rejected unsupported page-action version', { version: envelope.success.version });\n return { version: 1, id: envelopeId, ok: false, error: 'unsupportedVersion' };\n }\n\n const decoded = Schema.decodeUnknownResult(PageAction.InvokeRequest)(detail);\n if (Result.isFailure(decoded)) {\n log.info('rejected invalid page-action payload');\n return { version: 1, id: envelopeId, ok: false, error: 'invalidPayload' };\n }\n const request = decoded.success;\n\n const action = deps.getActions().find((candidate) => candidate.id === request.actionId);\n if (!action) {\n log.info('rejected unknown page action', { actionId: request.actionId });\n return { version: 1, id: request.id, ok: false, error: 'unknownAction' };\n }\n\n const target = deps.getTarget();\n if (!target) {\n return { version: 1, id: request.id, ok: false, error: 'noSpace' };\n }\n\n try {\n const { data, error } = await deps.invoke(action.operation, { snapshot: request.inputs, target });\n if (error || !data) {\n log.info('page-action operation failed', { actionId: action.id, error });\n return { version: 1, id: request.id, ok: false, error: 'operationFailed' };\n }\n log.info('page action invoked', { actionId: action.id, objectId: data.id });\n return { version: 1, id: request.id, ok: true, objectId: data.id };\n } catch (err) {\n log.catch(err);\n return { version: 1, id: request.id, ok: false, error: 'operationFailed' };\n }\n};\n\n/**\n * Attach the page-actions window event listeners. Returns a disposer.\n * Actions are resolved per-event via `getAll` so late-activating plugins are\n * always included.\n */\nexport const installPageActionListeners = (\n capabilities: CapabilityManager.CapabilityManager,\n invoker: Capabilities.OperationInvoker,\n onResult?: (ack: PageAction.InvokeAck, label?: string, spaceId?: SpaceId) => void,\n): (() => void) => {\n const getActions = () => capabilities.getAll(CrxCapabilities.PageAction).flat();\n\n const onList = (event: Event) => {\n const ack = handleListEvent((event as CustomEvent).detail, getActions);\n window.dispatchEvent(new CustomEvent(PageAction.LIST_ACK_EVENT, { detail: ack }));\n };\n\n const onInvoke = (event: Event) => {\n const detail = (event as CustomEvent).detail;\n // Resolved once so the ack's object is looked up in the space it was created in.\n let target: Database.Database | undefined;\n const deps: InvokeDeps = {\n getActions,\n getSettings: () => capabilities.get(Capabilities.AtomRegistry).get(capabilities.get(CrxCapabilities.Settings)),\n getTarget: () => {\n const client = capabilities.get(ClientCapabilities.Client);\n target = AppSpace.getActiveSpace(client, capabilities)?.db;\n return target;\n },\n invoke: (operation, input) => invoker.invokePromise(operation, input),\n };\n void handleInvokeEvent(detail, deps)\n .catch((err): PageAction.InvokeAck => {\n log.catch(err);\n return { version: 1, id: '', ok: false, error: 'operationFailed' };\n })\n .then((ack) => {\n window.dispatchEvent(new CustomEvent(PageAction.INVOKE_ACK_EVENT, { detail: ack }));\n try {\n const actionId = (detail as { actionId?: string } | null)?.actionId;\n onResult?.(ack, getActions().find((candidate) => candidate.id === actionId)?.label, target?.spaceId);\n } catch (err) {\n log.catch(err);\n }\n });\n };\n\n window.addEventListener(PageAction.LIST_EVENT, onList as EventListener);\n window.addEventListener(PageAction.INVOKE_EVENT, onInvoke as EventListener);\n\n // Announce that the page-side listeners are ready so the extension relay\n // can trigger a registry refresh even when Composer boots after the\n // content script has already installed.\n window.dispatchEvent(new CustomEvent(PageAction.READY_EVENT));\n\n return () => {\n window.removeEventListener(PageAction.LIST_EVENT, onList as EventListener);\n window.removeEventListener(PageAction.INVOKE_EVENT, onInvoke as EventListener);\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';\nimport * as NavigationOperation from '@dxos/app-toolkit/NavigationOperation';\nimport { EID, EntityId } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { meta } from '#meta';\nimport { CrxCapabilities, Settings } from '#types';\n\nimport { installPageActionListeners } from '../page-actions.ts';\n\nconst openObject = async (invoker: Capabilities.OperationInvoker, uri: EID.EID) => {\n const { data } = await invoker.invokePromise(NavigationOperation.ResolveNavigationTargets, { query: { uri } });\n const path = data?.targets[0]?.path;\n if (path) {\n await invoker.invokePromise(LayoutOperation.Open, { subject: [path] });\n }\n};\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilityManager = yield* Capability.Service;\n const invoker = yield* Capabilities.OperationInvoker;\n const registry = yield* Capabilities.AtomRegistry;\n const settingsAtom = yield* CrxCapabilities.Settings;\n\n // NOTE: The `Label` tuple only supports `ns`/`count`/`defaultValue`, so the\n // success toast uses a plain key rather than interpolating the action label.\n installPageActionListeners(capabilityManager, invoker, (ack, _label, spaceId) => {\n if (ack.ok) {\n void invoker.invokePromise(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.page-action-${ack.objectId ?? ack.id}`,\n title: ['toast.page-action.success.title', { ns: meta.profile.key }],\n });\n const entityId = ack.objectId;\n if (\n spaceId &&\n entityId &&\n EntityId.isValid(entityId) &&\n Settings.withDefaults(registry.get(settingsAtom)).autoOpenAfterClip\n ) {\n void openObject(invoker, EID.make({ spaceId, entityId }));\n }\n } else {\n void invoker.invokePromise(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.page-action-error-${Date.now()}`,\n title: ['toast.page-action.error.title', { ns: meta.profile.key }],\n description: [`toast.error.${ack.error}.message`, { ns: meta.profile.key }],\n });\n }\n });\n\n log.info('CRX page-actions bridge installed');\n\n return [];\n }),\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as Markdown from "@dxos/plugin-markdown/Markdown";
|
|
2
|
+
import { Organization, Person } from "@dxos/types";
|
|
3
|
+
//#region src/mapping.ts
|
|
4
|
+
var MAX_NOTES_LENGTH = 4e3;
|
|
5
|
+
/**
|
|
6
|
+
* Maximum length of the markdown body we write for a Note. Larger than
|
|
7
|
+
* the embedded `notes` field on Person/Organization because a Markdown
|
|
8
|
+
* document is the whole content, not a secondary annotation.
|
|
9
|
+
*/
|
|
10
|
+
var MAX_NOTE_BODY_LENGTH = 5e4;
|
|
11
|
+
var firstLine = (text) => {
|
|
12
|
+
if (!text) return;
|
|
13
|
+
const line = text.split("\n").map((s) => s.trim()).find((s) => s.length > 0);
|
|
14
|
+
return line && line.length > 0 ? line : void 0;
|
|
15
|
+
};
|
|
16
|
+
var truncate = (text, max) => {
|
|
17
|
+
if (!text) return;
|
|
18
|
+
return text.length > max ? text.slice(0, max) : text;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Best-effort mapping from an incoming page snapshot to a Person.
|
|
22
|
+
* Every field is optional on the schema, so an empty name is acceptable.
|
|
23
|
+
*/
|
|
24
|
+
var toPerson = (snapshot) => {
|
|
25
|
+
const hints = snapshot.hints ?? {};
|
|
26
|
+
const fullName = hints.h1 ?? hints.ogTitle ?? firstLine(snapshot.selection?.text);
|
|
27
|
+
return Person.make({
|
|
28
|
+
fullName,
|
|
29
|
+
image: hints.ogImage,
|
|
30
|
+
notes: truncate(snapshot.selection?.text, MAX_NOTES_LENGTH),
|
|
31
|
+
urls: [{
|
|
32
|
+
label: snapshot.source.title || snapshot.source.url,
|
|
33
|
+
value: snapshot.source.url
|
|
34
|
+
}]
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Best-effort mapping from an incoming page snapshot to an Organization.
|
|
39
|
+
*/
|
|
40
|
+
var toOrganization = (snapshot) => {
|
|
41
|
+
const hints = snapshot.hints ?? {};
|
|
42
|
+
const name = hints.ogTitle ?? hints.h1 ?? firstLine(snapshot.selection?.text);
|
|
43
|
+
return Organization.make({
|
|
44
|
+
name,
|
|
45
|
+
description: hints.ogDescription ?? truncate(snapshot.selection?.text, MAX_NOTES_LENGTH),
|
|
46
|
+
image: hints.ogImage,
|
|
47
|
+
website: snapshot.source.url
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Best-effort mapping from an incoming page snapshot to a Markdown document.
|
|
52
|
+
*
|
|
53
|
+
* Builds a small prelude (title + source link + date) followed by the
|
|
54
|
+
* picked subtree's rendered text. We deliberately don't attempt HTML →
|
|
55
|
+
* Markdown conversion here — the picker's `innerText` already preserves
|
|
56
|
+
* paragraph structure, and a full converter belongs in the pipeline
|
|
57
|
+
* (where a future agent stage can take over) rather than baked into the
|
|
58
|
+
* receiver.
|
|
59
|
+
*/
|
|
60
|
+
var toNote = (snapshot) => {
|
|
61
|
+
const hints = snapshot.hints ?? {};
|
|
62
|
+
const title = hints.h1 ?? hints.ogTitle ?? firstLine(snapshot.selection?.text) ?? snapshot.source.title;
|
|
63
|
+
const body = truncate(snapshot.selection?.text, MAX_NOTE_BODY_LENGTH) ?? "";
|
|
64
|
+
const sourceLabel = snapshot.source.title || snapshot.source.url;
|
|
65
|
+
const clippedAt = snapshot.source.clippedAt;
|
|
66
|
+
const content = [
|
|
67
|
+
title ? `# ${title}` : void 0,
|
|
68
|
+
"",
|
|
69
|
+
`_Clipped from [${sourceLabel}](${snapshot.source.url}) on ${clippedAt}._`,
|
|
70
|
+
"",
|
|
71
|
+
body
|
|
72
|
+
].filter((line) => line !== void 0).join("\n");
|
|
73
|
+
return Markdown.make({
|
|
74
|
+
name: title ?? void 0,
|
|
75
|
+
content
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
export { toOrganization as n, toPerson as r, toNote as t };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=chunk-mapping.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-mapping.mjs","names":[],"sources":["../../src/mapping.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Markdown from '@dxos/plugin-markdown/Markdown';\nimport { Organization, Person } from '@dxos/types';\n\nimport { PageAction } from '#types';\n\nconst MAX_NOTES_LENGTH = 4000;\n\n/**\n * Maximum length of the markdown body we write for a Note. Larger than\n * the embedded `notes` field on Person/Organization because a Markdown\n * document is the whole content, not a secondary annotation.\n */\nconst MAX_NOTE_BODY_LENGTH = 50_000;\n\nconst firstLine = (text: string | undefined): string | undefined => {\n if (!text) {\n return undefined;\n }\n const line = text\n .split('\\n')\n .map((s) => s.trim())\n .find((s) => s.length > 0);\n return line && line.length > 0 ? line : undefined;\n};\n\nconst truncate = (text: string | undefined, max: number): string | undefined => {\n if (!text) {\n return undefined;\n }\n return text.length > max ? text.slice(0, max) : text;\n};\n\n/**\n * Best-effort mapping from an incoming page snapshot to a Person.\n * Every field is optional on the schema, so an empty name is acceptable.\n */\nexport const toPerson = (snapshot: PageAction.Snapshot) => {\n const hints = snapshot.hints ?? {};\n const fullName = hints.h1 ?? hints.ogTitle ?? firstLine(snapshot.selection?.text);\n return Person.make({\n fullName,\n image: hints.ogImage,\n notes: truncate(snapshot.selection?.text, MAX_NOTES_LENGTH),\n urls: [\n {\n label: snapshot.source.title || snapshot.source.url,\n value: snapshot.source.url,\n },\n ],\n });\n};\n\n/**\n * Best-effort mapping from an incoming page snapshot to an Organization.\n */\nexport const toOrganization = (snapshot: PageAction.Snapshot) => {\n const hints = snapshot.hints ?? {};\n const name = hints.ogTitle ?? hints.h1 ?? firstLine(snapshot.selection?.text);\n return Organization.make({\n name,\n description: hints.ogDescription ?? truncate(snapshot.selection?.text, MAX_NOTES_LENGTH),\n image: hints.ogImage,\n website: snapshot.source.url,\n });\n};\n\n/**\n * Best-effort mapping from an incoming page snapshot to a Markdown document.\n *\n * Builds a small prelude (title + source link + date) followed by the\n * picked subtree's rendered text. We deliberately don't attempt HTML →\n * Markdown conversion here — the picker's `innerText` already preserves\n * paragraph structure, and a full converter belongs in the pipeline\n * (where a future agent stage can take over) rather than baked into the\n * receiver.\n */\nexport const toNote = (snapshot: PageAction.Snapshot) => {\n const hints = snapshot.hints ?? {};\n const title = hints.h1 ?? hints.ogTitle ?? firstLine(snapshot.selection?.text) ?? snapshot.source.title;\n const body = truncate(snapshot.selection?.text, MAX_NOTE_BODY_LENGTH) ?? '';\n\n const sourceLabel = snapshot.source.title || snapshot.source.url;\n const clippedAt = snapshot.source.clippedAt;\n const preludeLines = [\n title ? `# ${title}` : undefined,\n '',\n `_Clipped from [${sourceLabel}](${snapshot.source.url}) on ${clippedAt}._`,\n '',\n body,\n ].filter((line): line is string => line !== undefined);\n const content = preludeLines.join('\\n');\n\n return Markdown.make({\n name: title ?? undefined,\n content,\n });\n};\n"],"mappings":";;;AASA,IAAM,mBAAmB;;;;;;AAOzB,IAAM,uBAAuB;AAE7B,IAAM,aAAa,SAAiD;CAClE,IAAI,CAAC,MACH;CAEF,MAAM,OAAO,KACV,MAAM,IAAI,CAAA,CACV,KAAK,MAAM,EAAE,KAAK,CAAC,CAAA,CACnB,MAAM,MAAM,EAAE,SAAS,CAAC;CAC3B,OAAO,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAA;AAC1C;AAEA,IAAM,YAAY,MAA0B,QAAoC;CAC9E,IAAI,CAAC,MACH;CAEF,OAAO,KAAK,SAAS,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI;AAClD;;;;;AAMA,IAAa,YAAY,aAAkC;CACzD,MAAM,QAAQ,SAAS,SAAS,CAAC;CACjC,MAAM,WAAW,MAAM,MAAM,MAAM,WAAW,UAAU,SAAS,WAAW,IAAI;CAChF,OAAO,OAAO,KAAK;EACjB;EACA,OAAO,MAAM;EACb,OAAO,SAAS,SAAS,WAAW,MAAM,gBAAgB;EAC1D,MAAM,CACJ;GACE,OAAO,SAAS,OAAO,SAAS,SAAS,OAAO;GAChD,OAAO,SAAS,OAAO;EACzB,CACF;CACF,CAAC;AACH;;;;AAKA,IAAa,kBAAkB,aAAkC;CAC/D,MAAM,QAAQ,SAAS,SAAS,CAAC;CACjC,MAAM,OAAO,MAAM,WAAW,MAAM,MAAM,UAAU,SAAS,WAAW,IAAI;CAC5E,OAAO,aAAa,KAAK;EACvB;EACA,aAAa,MAAM,iBAAiB,SAAS,SAAS,WAAW,MAAM,gBAAgB;EACvF,OAAO,MAAM;EACb,SAAS,SAAS,OAAO;CAC3B,CAAC;AACH;;;;;;;;;;;AAYA,IAAa,UAAU,aAAkC;CACvD,MAAM,QAAQ,SAAS,SAAS,CAAC;CACjC,MAAM,QAAQ,MAAM,MAAM,MAAM,WAAW,UAAU,SAAS,WAAW,IAAI,KAAK,SAAS,OAAO;CAClG,MAAM,OAAO,SAAS,SAAS,WAAW,MAAM,oBAAoB,KAAK;CAEzE,MAAM,cAAc,SAAS,OAAO,SAAS,SAAS,OAAO;CAC7D,MAAM,YAAY,SAAS,OAAO;CAQlC,MAAM,UAPe;EACnB,QAAQ,KAAK,UAAU,KAAA;EACvB;EACA,kBAAkB,YAAY,IAAI,SAAS,OAAO,IAAI,OAAO,UAAU;EACvE;EACA;CACF,CAAC,CAAC,QAAQ,SAAyB,SAAS,KAAA,CAC5B,CAAA,CAAa,KAAK,IAAI;CAEtC,OAAO,SAAS,KAAK;EACnB,MAAM,SAAS,KAAA;EACf;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import { CrxOperationHandlerSet } from "#operations";
|
|
5
|
+
//#region src/capabilities/operation-handler.ts
|
|
6
|
+
var operation_handler_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
7
|
+
return Capability.contribute(Capabilities.OperationHandler, CrxOperationHandlerSet);
|
|
8
|
+
}));
|
|
9
|
+
//#endregion
|
|
10
|
+
export { operation_handler_default as default };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=chunk-operation-handler.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-operation-handler.mjs","names":[],"sources":["../../src/capabilities/operation-handler.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\n\nimport { CrxOperationHandlerSet } from '#operations';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(Capabilities.OperationHandler, CrxOperationHandlerSet);\n }),\n);\n"],"mappings":";;;;;AAWA,IAAA,4BAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,aAAa,kBAAkB,sBAAsB;AACpF,CAAC,CACH"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
2
|
+
import { CrxCapabilities, CrxOperation } from "#types";
|
|
3
|
+
import { meta } from "#meta";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
//#region src/capabilities/page-action-provider.ts
|
|
6
|
+
var page_action_provider_default = Capability.makeModule(() => Effect.sync(() => {
|
|
7
|
+
const actions = [
|
|
8
|
+
{
|
|
9
|
+
id: `${meta.profile.key}/page-action/add-person`,
|
|
10
|
+
label: "Person",
|
|
11
|
+
icon: "ph--user--regular",
|
|
12
|
+
urlPatterns: ["http://*/*", "https://*/*"],
|
|
13
|
+
extractor: { name: "snapshot" },
|
|
14
|
+
contexts: ["picker"],
|
|
15
|
+
operation: CrxOperation.AddPersonFromSnapshot
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: `${meta.profile.key}/page-action/add-organization`,
|
|
19
|
+
label: "Organization",
|
|
20
|
+
icon: "ph--building-office--regular",
|
|
21
|
+
urlPatterns: ["http://*/*", "https://*/*"],
|
|
22
|
+
extractor: { name: "snapshot" },
|
|
23
|
+
contexts: ["picker"],
|
|
24
|
+
operation: CrxOperation.AddOrganizationFromSnapshot
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: `${meta.profile.key}/page-action/add-note`,
|
|
28
|
+
label: "Note",
|
|
29
|
+
icon: "ph--note--regular",
|
|
30
|
+
urlPatterns: ["http://*/*", "https://*/*"],
|
|
31
|
+
extractor: { name: "snapshot" },
|
|
32
|
+
contexts: ["picker"],
|
|
33
|
+
operation: CrxOperation.AddNoteFromSnapshot
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
return Capability.contribute(CrxCapabilities.PageAction, actions);
|
|
37
|
+
}));
|
|
38
|
+
//#endregion
|
|
39
|
+
export { page_action_provider_default as default };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=chunk-page-action-provider.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-page-action-provider.mjs","names":[],"sources":["../../src/capabilities/page-action-provider.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\n\nimport { meta } from '#meta';\nimport { CrxCapabilities, CrxOperation, PageAction } from '#types';\n\nexport default Capability.makeModule(() =>\n Effect.sync(() => {\n // Picker-only: these actions back the extension's DOM-picker toolbar and\n // are not surfaced in the popup or context menu.\n const actions: PageAction.PageAction[] = [\n {\n id: `${meta.profile.key}/page-action/add-person`,\n label: 'Person',\n icon: 'ph--user--regular',\n urlPatterns: ['http://*/*', 'https://*/*'],\n extractor: { name: 'snapshot' },\n contexts: ['picker'],\n operation: CrxOperation.AddPersonFromSnapshot,\n },\n {\n id: `${meta.profile.key}/page-action/add-organization`,\n label: 'Organization',\n icon: 'ph--building-office--regular',\n urlPatterns: ['http://*/*', 'https://*/*'],\n extractor: { name: 'snapshot' },\n contexts: ['picker'],\n operation: CrxOperation.AddOrganizationFromSnapshot,\n },\n {\n id: `${meta.profile.key}/page-action/add-note`,\n label: 'Note',\n icon: 'ph--note--regular',\n urlPatterns: ['http://*/*', 'https://*/*'],\n extractor: { name: 'snapshot' },\n contexts: ['picker'],\n operation: CrxOperation.AddNoteFromSnapshot,\n },\n ];\n return Capability.contribute(CrxCapabilities.PageAction, actions);\n }),\n);\n"],"mappings":";;;;;AAWA,IAAA,+BAAe,WAAW,iBACxB,OAAO,WAAW;CAGhB,MAAM,UAAmC;EACvC;GACE,IAAI,GAAG,KAAK,QAAQ,IAAI;GACxB,OAAO;GACP,MAAM;GACN,aAAa,CAAC,cAAc,aAAa;GACzC,WAAW,EAAE,MAAM,WAAW;GAC9B,UAAU,CAAC,QAAQ;GACnB,WAAW,aAAa;EAC1B;EACA;GACE,IAAI,GAAG,KAAK,QAAQ,IAAI;GACxB,OAAO;GACP,MAAM;GACN,aAAa,CAAC,cAAc,aAAa;GACzC,WAAW,EAAE,MAAM,WAAW;GAC9B,UAAU,CAAC,QAAQ;GACnB,WAAW,aAAa;EAC1B;EACA;GACE,IAAI,GAAG,KAAK,QAAQ,IAAI;GACxB,OAAO;GACP,MAAM;GACN,aAAa,CAAC,cAAc,aAAa;GACzC,WAAW,EAAE,MAAM,WAAW;GAC9B,UAAU,CAAC,QAAQ;GACnB,WAAW,aAAa;EAC1B;CACF;CACA,OAAO,WAAW,WAAW,gBAAgB,YAAY,OAAO;AAClE,CAAC,CACH"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import { meta } from "#meta";
|
|
4
|
+
import { Surface } from "@dxos/app-framework/ui";
|
|
5
|
+
import { AppSurface } from "@dxos/app-toolkit/ui";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import { CrxSettings } from "#containers";
|
|
8
|
+
//#region src/capabilities/react-surface.ts
|
|
9
|
+
var react_surface_default = Capability.makeModule(() => Effect.succeed(Capability.contribute(Capabilities.ReactSurface, [Surface.create({
|
|
10
|
+
id: "pluginSettings",
|
|
11
|
+
filter: AppSurface.settings(AppSurface.Article, meta.profile.key),
|
|
12
|
+
component: CrxSettings,
|
|
13
|
+
props: ({ data: { subject } }) => ({ subject })
|
|
14
|
+
})])));
|
|
15
|
+
//#endregion
|
|
16
|
+
export { react_surface_default as default };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=chunk-react-surface.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { Surface } from '@dxos/app-framework/ui';\nimport { AppSurface } from '@dxos/app-toolkit/ui';\n\nimport { CrxSettings } from '#containers';\nimport { meta } from '#meta';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(Capabilities.ReactSurface, [\n Surface.create({\n id: 'pluginSettings',\n filter: AppSurface.settings(AppSurface.Article, meta.profile.key),\n component: CrxSettings,\n props: ({ data: { subject } }) => ({ subject }),\n }),\n ]),\n ),\n);\n"],"mappings":";;;;;;;;AAcA,IAAA,wBAAe,WAAW,iBACxB,OAAO,QACL,WAAW,WAAW,aAAa,cAAc,CAC/C,QAAQ,OAAO;CACb,IAAI;CACJ,QAAQ,WAAW,SAAS,WAAW,SAAS,KAAK,QAAQ,GAAG;CAChE,WAAW;CACX,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ;AAC/C,CAAC,CACH,CAAC,CACH,CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
2
|
+
import { CrxCapabilities, Settings } from "#types";
|
|
3
|
+
import { meta } from "#meta";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as AppCapabilities from "@dxos/app-toolkit/AppCapabilities";
|
|
6
|
+
import { createKvsStore } from "@dxos/effect";
|
|
7
|
+
//#region src/capabilities/settings.ts
|
|
8
|
+
/**
|
|
9
|
+
* Contributes the Settings atom both under the plugin-scoped capability (so
|
|
10
|
+
* other plugins can read it) and under `AppCapabilities.Settings` (so the
|
|
11
|
+
* standard settings panel surfaces it).
|
|
12
|
+
*/
|
|
13
|
+
var settings_default = Capability.makeModule(() => Effect.sync(() => {
|
|
14
|
+
const settingsAtom = createKvsStore({
|
|
15
|
+
key: meta.profile.key,
|
|
16
|
+
schema: Settings.Settings,
|
|
17
|
+
defaultValue: () => Settings.defaults
|
|
18
|
+
});
|
|
19
|
+
return [Capability.contribute(CrxCapabilities.Settings, settingsAtom), Capability.contribute(AppCapabilities.Settings, {
|
|
20
|
+
prefix: meta.profile.key,
|
|
21
|
+
schema: Settings.Settings,
|
|
22
|
+
atom: settingsAtom
|
|
23
|
+
})];
|
|
24
|
+
}));
|
|
25
|
+
//#endregion
|
|
26
|
+
export { settings_default as default };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=chunk-settings.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-settings.mjs","names":[],"sources":["../../src/capabilities/settings.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport { createKvsStore } from '@dxos/effect';\n\nimport { meta } from '#meta';\nimport { CrxCapabilities, Settings } from '#types';\n\n/**\n * Contributes the Settings atom both under the plugin-scoped capability (so\n * other plugins can read it) and under `AppCapabilities.Settings` (so the\n * standard settings panel surfaces it).\n */\nexport default Capability.makeModule(() =>\n Effect.sync(() => {\n const settingsAtom = createKvsStore({\n key: meta.profile.key,\n schema: Settings.Settings,\n defaultValue: () => Settings.defaults,\n });\n\n return [\n Capability.contribute(CrxCapabilities.Settings, settingsAtom),\n Capability.contribute(AppCapabilities.Settings, {\n prefix: meta.profile.key,\n schema: Settings.Settings,\n atom: settingsAtom,\n }),\n ];\n }),\n);\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAA,mBAAe,WAAW,iBACxB,OAAO,WAAW;CAChB,MAAM,eAAe,eAAe;EAClC,KAAK,KAAK,QAAQ;EAClB,QAAQ,SAAS;EACjB,oBAAoB,SAAS;CAC/B,CAAC;CAED,OAAO,CACL,WAAW,WAAW,gBAAgB,UAAU,YAAY,GAC5D,WAAW,WAAW,gBAAgB,UAAU;EAC9C,QAAQ,KAAK,QAAQ;EACrB,QAAQ,SAAS;EACjB,MAAM;CACR,CAAC,CACH;AACF,CAAC,CACH"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { pingExtension } from "./util.mjs";
|
|
2
|
+
import { Settings } from "#types";
|
|
3
|
+
import { meta } from "#meta";
|
|
4
|
+
import { useCallback, useState } from "react";
|
|
5
|
+
import { useSettingsState } from "@dxos/app-framework/ui";
|
|
6
|
+
import { SettingsScope } from "@dxos/app-toolkit/ui";
|
|
7
|
+
import { Flex, IconButton, useTranslation } from "@dxos/react-ui";
|
|
8
|
+
import { Form } from "@dxos/react-ui-form";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/containers/CrxSettings/CrxSettings.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Settings panel for the browser extension: edits the plugin's schema-driven settings and offers a
|
|
13
|
+
* round-trip connection test against the extension's content relay.
|
|
14
|
+
*/
|
|
15
|
+
var CrxSettings = ({ subject, readonly }) => {
|
|
16
|
+
const { t } = useTranslation(meta.profile.key);
|
|
17
|
+
const { settings, updateSettings } = useSettingsState(subject.atom);
|
|
18
|
+
const [test, setTest] = useState({ kind: "idle" });
|
|
19
|
+
const handleTest = useCallback(async () => {
|
|
20
|
+
setTest({ kind: "pending" });
|
|
21
|
+
try {
|
|
22
|
+
const info = await pingExtension();
|
|
23
|
+
setTest({
|
|
24
|
+
kind: "ok",
|
|
25
|
+
message: t("test.connected.message", {
|
|
26
|
+
name: info.extensionName,
|
|
27
|
+
version: info.extensionVersion
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
} catch (err) {
|
|
31
|
+
setTest({
|
|
32
|
+
kind: "error",
|
|
33
|
+
message: err instanceof Error ? err.message : String(err)
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}, [t]);
|
|
37
|
+
return /* @__PURE__ */ jsx(Form.Root, {
|
|
38
|
+
schema: Settings.Settings,
|
|
39
|
+
values: settings,
|
|
40
|
+
variant: "settings",
|
|
41
|
+
readonly,
|
|
42
|
+
onValuesChanged: (values) => updateSettings((current) => ({
|
|
43
|
+
...current,
|
|
44
|
+
...values
|
|
45
|
+
})),
|
|
46
|
+
children: /* @__PURE__ */ jsx(Form.Viewport, {
|
|
47
|
+
scroll: true,
|
|
48
|
+
children: /* @__PURE__ */ jsxs(Form.Content, { children: [/* @__PURE__ */ jsx(Form.FieldSet, {
|
|
49
|
+
label: meta.profile.name ?? meta.profile.key,
|
|
50
|
+
description: t("settings.description"),
|
|
51
|
+
actions: readonly ? void 0 : /* @__PURE__ */ jsx(SettingsScope, { prefix: subject.prefix }),
|
|
52
|
+
children: /* @__PURE__ */ jsx(Form.Fields, {})
|
|
53
|
+
}), /* @__PURE__ */ jsx(Form.FieldSet, {
|
|
54
|
+
label: t("test.title"),
|
|
55
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
56
|
+
gap: "sm",
|
|
57
|
+
children: [/* @__PURE__ */ jsx(IconButton, {
|
|
58
|
+
disabled: test.kind === "pending",
|
|
59
|
+
icon: "ph--plug--regular",
|
|
60
|
+
label: t("test.button.label"),
|
|
61
|
+
onClick: handleTest
|
|
62
|
+
}), /* @__PURE__ */ jsx(Flex, {
|
|
63
|
+
align: "center",
|
|
64
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
65
|
+
role: "status",
|
|
66
|
+
"aria-live": "polite",
|
|
67
|
+
className: test.kind === "ok" ? "text-sm text-success-text" : test.kind === "error" ? "text-sm text-error-text" : "text-sm text-description",
|
|
68
|
+
children: [test.kind === "ok" || test.kind === "error" ? test.message : "", test.kind === "pending" ? t("test.pending.message") : ""]
|
|
69
|
+
})
|
|
70
|
+
})]
|
|
71
|
+
})
|
|
72
|
+
})] })
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
CrxSettings.displayName = "CrxSettings";
|
|
77
|
+
//#endregion
|
|
78
|
+
export { CrxSettings };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=containers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containers.mjs","names":[],"sources":["../../src/containers/CrxSettings/CrxSettings.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useCallback, useState } from 'react';\n\nimport { useSettingsState } from '@dxos/app-framework/ui';\nimport { type AppSurface, SettingsScope } from '@dxos/app-toolkit/ui';\nimport { Flex, IconButton, useTranslation } from '@dxos/react-ui';\nimport { Form } from '@dxos/react-ui-form';\n\nimport { meta } from '#meta';\nimport { Settings } from '#types';\n\nimport { pingExtension } from '../../util/index.ts';\n\ntype TestState =\n | { kind: 'idle' }\n | { kind: 'pending' }\n | { kind: 'ok'; message: string }\n | { kind: 'error'; message: string };\n\nexport type CrxSettingsProps = AppSurface.SettingsData<{ readonly?: boolean }>;\n\n/**\n * Settings panel for the browser extension: edits the plugin's schema-driven settings and offers a\n * round-trip connection test against the extension's content relay.\n */\nexport const CrxSettings = ({ subject, readonly }: CrxSettingsProps) => {\n const { t } = useTranslation(meta.profile.key);\n const { settings, updateSettings } = useSettingsState<Settings.Settings>(subject.atom);\n const [test, setTest] = useState<TestState>({ kind: 'idle' });\n\n // Round-trip a ping to the extension and report its identity (or why it failed).\n const handleTest = useCallback(async () => {\n setTest({ kind: 'pending' });\n try {\n const info = await pingExtension();\n setTest({\n kind: 'ok',\n message: t('test.connected.message', { name: info.extensionName, version: info.extensionVersion }),\n });\n } catch (err) {\n setTest({ kind: 'error', message: err instanceof Error ? err.message : String(err) });\n }\n }, [t]);\n\n return (\n <Form.Root\n schema={Settings.Settings}\n values={settings}\n variant='settings'\n readonly={readonly}\n onValuesChanged={(values) => updateSettings((current) => ({ ...current, ...values }))}\n >\n <Form.Viewport scroll>\n <Form.Content>\n <Form.FieldSet\n label={meta.profile.name ?? meta.profile.key}\n description={t('settings.description')}\n actions={readonly ? undefined : <SettingsScope prefix={subject.prefix} />}\n >\n <Form.Fields />\n </Form.FieldSet>\n\n <Form.FieldSet label={t('test.title')}>\n <Flex gap='sm'>\n <IconButton\n disabled={test.kind === 'pending'}\n icon='ph--plug--regular'\n label={t('test.button.label')}\n onClick={handleTest}\n />\n\n {/* role=status + aria-live so screen readers announce the async outcome. */}\n <Flex align='center'>\n <span\n role='status'\n aria-live='polite'\n className={\n test.kind === 'ok'\n ? 'text-sm text-success-text'\n : test.kind === 'error'\n ? 'text-sm text-error-text'\n : 'text-sm text-description'\n }\n >\n {test.kind === 'ok' || test.kind === 'error' ? test.message : ''}\n {test.kind === 'pending' ? t('test.pending.message') : ''}\n </span>\n </Flex>\n </Flex>\n </Form.FieldSet>\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n );\n};\n\nCrxSettings.displayName = 'CrxSettings';\n"],"mappings":";;;;;;;;;;;;;;AA4BA,IAAa,eAAe,EAAE,SAAS,eAAiC;CACtE,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,EAAE,UAAU,mBAAmB,iBAAoC,QAAQ,IAAI;CACrF,MAAM,CAAC,MAAM,WAAW,SAAoB,EAAE,MAAM,OAAO,CAAC;CAG5D,MAAM,aAAa,YAAY,YAAY;EACzC,QAAQ,EAAE,MAAM,UAAU,CAAC;EAC3B,IAAI;GACF,MAAM,OAAO,MAAM,cAAc;GACjC,QAAQ;IACN,MAAM;IACN,SAAS,EAAE,0BAA0B;KAAE,MAAM,KAAK;KAAe,SAAS,KAAK;IAAiB,CAAC;GACnG,CAAC;EACH,SAAS,KAAK;GACZ,QAAQ;IAAE,MAAM;IAAS,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAAE,CAAC;EACtF;CACF,GAAG,CAAC,CAAC,CAAC;CAEN,OACE,oBAAC,KAAK,MAAN;EACE,QAAQ,SAAS;EACjB,QAAQ;EACR,SAAQ;EACE;EACV,kBAAkB,WAAW,gBAAgB,aAAa;GAAE,GAAG;GAAS,GAAG;EAAO,EAAE;EAEpF,UAAA,oBAAC,KAAK,UAAN;GAAe,QAAA;GACb,UAAA,qBAAC,KAAK,SAAN,EAAA,UAAA,CACE,oBAAC,KAAK,UAAN;IACE,OAAO,KAAK,QAAQ,QAAQ,KAAK,QAAQ;IACzC,aAAa,EAAE,sBAAsB;IACrC,SAAS,WAAW,KAAA,IAAY,oBAAC,eAAD,EAAe,QAAQ,QAAQ,OAAS,CAAA;IAExE,UAAA,oBAAC,KAAK,QAAN,CAAc,CAAA;GACD,CAAA,GAEf,oBAAC,KAAK,UAAN;IAAe,OAAO,EAAE,YAAY;IAClC,UAAA,qBAAC,MAAD;KAAM,KAAI;KAAV,UAAA,CACE,oBAAC,YAAD;MACE,UAAU,KAAK,SAAS;MACxB,MAAK;MACL,OAAO,EAAE,mBAAmB;MAC5B,SAAS;KACV,CAAA,GAGD,oBAAC,MAAD;MAAM,OAAM;MACV,UAAA,qBAAC,QAAD;OACE,MAAK;OACL,aAAU;OACV,WACE,KAAK,SAAS,OACV,8BACA,KAAK,SAAS,UACZ,4BACA;OARV,UAAA,CAWG,KAAK,SAAS,QAAQ,KAAK,SAAS,UAAU,KAAK,UAAU,IAC7D,KAAK,SAAS,YAAY,EAAE,sBAAsB,IAAI,EACnD;;KACF,CAAA,CACF;;GACO,CAAA,CACH,EAAA,CAAA;EACD,CAAA;CACN,CAAA;AAEf;AAEA,YAAY,cAAc"}
|