@kehto/services 0.22.0 → 0.23.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/README.md +33 -30
- package/dist/index.d.ts +127 -184
- package/dist/index.js +236 -348
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1339,11 +1339,11 @@ function hasSourceRef(source) {
|
|
|
1339
1339
|
}
|
|
1340
1340
|
function canonicalizeSessionId(state, windowId, preferredSessionId) {
|
|
1341
1341
|
const trimmed = typeof preferredSessionId === "string" ? preferredSessionId.trim() : "";
|
|
1342
|
-
const
|
|
1343
|
-
if (!state.sessionRegistry.has(
|
|
1342
|
+
const hint2 = trimmed || `session-${++state.sessionCounter}`;
|
|
1343
|
+
if (!state.sessionRegistry.has(hint2)) return hint2;
|
|
1344
1344
|
let next;
|
|
1345
1345
|
do {
|
|
1346
|
-
next = `${windowId}:${
|
|
1346
|
+
next = `${windowId}:${hint2}:${++state.sessionCounter}`;
|
|
1347
1347
|
} while (state.sessionRegistry.has(next));
|
|
1348
1348
|
return next;
|
|
1349
1349
|
}
|
|
@@ -2167,14 +2167,14 @@ var ConfigServiceController = class {
|
|
|
2167
2167
|
}
|
|
2168
2168
|
}
|
|
2169
2169
|
handleOpenSettings(windowId, message, send) {
|
|
2170
|
-
const
|
|
2171
|
-
if (!
|
|
2170
|
+
const record2 = this.schemas.get(windowId);
|
|
2171
|
+
if (!record2) {
|
|
2172
2172
|
sendSchemaError(send, "no-schema", "no configuration schema is registered");
|
|
2173
2173
|
return;
|
|
2174
2174
|
}
|
|
2175
2175
|
let values;
|
|
2176
2176
|
try {
|
|
2177
|
-
values = resolveConfigValues(
|
|
2177
|
+
values = resolveConfigValues(record2.schema, this.options.getValues(windowId));
|
|
2178
2178
|
} catch (cause) {
|
|
2179
2179
|
sendSchemaError(
|
|
2180
2180
|
send,
|
|
@@ -2183,9 +2183,9 @@ var ConfigServiceController = class {
|
|
|
2183
2183
|
);
|
|
2184
2184
|
return;
|
|
2185
2185
|
}
|
|
2186
|
-
const section = message.section && schemaHasSection(
|
|
2186
|
+
const section = message.section && schemaHasSection(record2.schema, message.section) ? message.section : void 0;
|
|
2187
2187
|
this.options.openSettings?.(windowId, section, {
|
|
2188
|
-
schema: structuredClone(
|
|
2188
|
+
schema: structuredClone(record2.schema),
|
|
2189
2189
|
values,
|
|
2190
2190
|
commit: (next) => this.commitValues(windowId, next)
|
|
2191
2191
|
});
|
|
@@ -3711,371 +3711,256 @@ function toErrorMessage3(err2) {
|
|
|
3711
3711
|
}
|
|
3712
3712
|
|
|
3713
3713
|
// src/intent-service.ts
|
|
3714
|
-
var INTENT_SERVICE_VERSION = "1.0.0";
|
|
3715
3714
|
var INTENT_DESCRIPTOR = {
|
|
3716
3715
|
name: "intent",
|
|
3717
|
-
version:
|
|
3718
|
-
description: "NAP-INTENT
|
|
3716
|
+
version: "1.0.0",
|
|
3717
|
+
description: "NAP-INTENT convention dispatch"
|
|
3719
3718
|
};
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
return "intent request failed";
|
|
3724
|
-
}
|
|
3725
|
-
function hasOwn(value, key) {
|
|
3719
|
+
var CONVENTION = /^napplet:([a-z0-9][a-z0-9-]*)\/([a-z0-9][a-z0-9-]*)$/;
|
|
3720
|
+
var HINT_ADDRESS = /^35129:[a-f0-9]{64}:.+$/;
|
|
3721
|
+
function own(value, key) {
|
|
3726
3722
|
return Object.prototype.hasOwnProperty.call(value, key);
|
|
3727
3723
|
}
|
|
3728
|
-
function
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
const
|
|
3733
|
-
if (typeof
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
}
|
|
3740
|
-
if (request.convention !== void 0 && (typeof request.convention !== "string" || !/^napplet:[^/?#\s]+\/[^/?#\s]+$/.test(request.convention))) {
|
|
3741
|
-
return { error: "invalid convention" };
|
|
3742
|
-
}
|
|
3743
|
-
const allowedKeys = ["archetype", "action", "convention", "payload", "handler", "behavior"];
|
|
3744
|
-
if (Object.keys(request).some((key) => !allowedKeys.includes(key))) {
|
|
3745
|
-
return { error: "invoke rejected" };
|
|
3746
|
-
}
|
|
3747
|
-
if (hasOwn(request, "handler") && request.handler !== void 0 && (typeof request.handler !== "string" || request.handler.length === 0)) {
|
|
3748
|
-
return { error: "invoke rejected" };
|
|
3749
|
-
}
|
|
3750
|
-
let behavior;
|
|
3751
|
-
if (hasOwn(request, "behavior") && request.behavior !== void 0) {
|
|
3752
|
-
if (typeof request.behavior !== "object" || request.behavior === null || Array.isArray(request.behavior)) {
|
|
3753
|
-
return { error: "invoke rejected" };
|
|
3754
|
-
}
|
|
3755
|
-
const record = request.behavior;
|
|
3756
|
-
if (Object.keys(record).some((key) => key !== "focus" && key !== "newWindow" && key !== "reuse") || hasOwn(record, "focus") && typeof record.focus !== "boolean" || hasOwn(record, "newWindow") && typeof record.newWindow !== "boolean" || hasOwn(record, "reuse") && typeof record.reuse !== "boolean") {
|
|
3757
|
-
return { error: "invoke rejected" };
|
|
3758
|
-
}
|
|
3759
|
-
behavior = {
|
|
3760
|
-
...record.focus === void 0 ? {} : { focus: record.focus },
|
|
3761
|
-
...record.newWindow === void 0 ? {} : { newWindow: record.newWindow },
|
|
3762
|
-
...record.reuse === void 0 ? {} : { reuse: record.reuse }
|
|
3763
|
-
};
|
|
3764
|
-
}
|
|
3765
|
-
return {
|
|
3766
|
-
request: {
|
|
3767
|
-
archetype: request.archetype,
|
|
3768
|
-
action,
|
|
3769
|
-
...typeof request.convention === "string" ? { convention: request.convention } : {},
|
|
3770
|
-
...hasOwn(request, "payload") ? { payload: request.payload } : {},
|
|
3771
|
-
...typeof request.handler === "string" ? { handler: request.handler } : {},
|
|
3772
|
-
...behavior === void 0 ? {} : { behavior }
|
|
3773
|
-
}
|
|
3774
|
-
};
|
|
3775
|
-
}
|
|
3776
|
-
function settleResolverCall(call, send, resultType, id, onValue) {
|
|
3777
|
-
let pending;
|
|
3778
|
-
try {
|
|
3779
|
-
pending = Promise.resolve(call());
|
|
3780
|
-
} catch (error) {
|
|
3781
|
-
send({ type: resultType, id, error: toErrorMessage4(error) });
|
|
3782
|
-
return;
|
|
3783
|
-
}
|
|
3784
|
-
pending.then((value) => send(onValue(value))).catch((error) => send({ type: resultType, id, error: toErrorMessage4(error) }));
|
|
3785
|
-
}
|
|
3786
|
-
function rejectedResult(request, error) {
|
|
3787
|
-
return {
|
|
3788
|
-
ok: false,
|
|
3789
|
-
archetype: request.archetype,
|
|
3790
|
-
action: request.action ?? "open",
|
|
3791
|
-
handled: false,
|
|
3792
|
-
error
|
|
3793
|
-
};
|
|
3724
|
+
function record(value) {
|
|
3725
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
3726
|
+
}
|
|
3727
|
+
function hint(value) {
|
|
3728
|
+
const source = record(value);
|
|
3729
|
+
if (!source || !own(source, "address") || typeof source.address !== "string" || !HINT_ADDRESS.test(source.address)) return void 0;
|
|
3730
|
+
if (Object.keys(source).some((key) => key !== "address" && key !== "relays")) return void 0;
|
|
3731
|
+
if (source.relays !== void 0 && (!Array.isArray(source.relays) || source.relays.some((relay) => typeof relay !== "string"))) return void 0;
|
|
3732
|
+
return Object.freeze({
|
|
3733
|
+
address: source.address,
|
|
3734
|
+
...source.relays === void 0 ? {} : { relays: Object.freeze([...source.relays]) }
|
|
3735
|
+
});
|
|
3794
3736
|
}
|
|
3795
|
-
function
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3737
|
+
function validateRequest(value) {
|
|
3738
|
+
const source = record(value);
|
|
3739
|
+
if (!source || !own(source, "archetype") || !own(source, "action") || !own(source, "convention")) return void 0;
|
|
3740
|
+
if (Object.keys(source).some((key) => !["archetype", "action", "convention", "payload", "handler", "handlerHint", "behavior"].includes(key))) return void 0;
|
|
3741
|
+
if (typeof source.archetype !== "string" || typeof source.action !== "string" || typeof source.convention !== "string") return void 0;
|
|
3742
|
+
const match = CONVENTION.exec(source.convention);
|
|
3743
|
+
if (!match || match[1] !== source.archetype || match[2] !== source.action) return void 0;
|
|
3744
|
+
if (source.handler !== void 0 && (typeof source.handler !== "string" || source.handler.length === 0)) return void 0;
|
|
3745
|
+
const parsedHint = source.handlerHint === void 0 ? void 0 : hint(source.handlerHint);
|
|
3746
|
+
if (source.handlerHint !== void 0 && !parsedHint) return void 0;
|
|
3747
|
+
const rawBehavior = source.behavior === void 0 ? void 0 : record(source.behavior);
|
|
3748
|
+
if (source.behavior !== void 0 && (!rawBehavior || Object.keys(rawBehavior).some((key) => key !== "focus" && key !== "reuse") || rawBehavior.focus !== void 0 && typeof rawBehavior.focus !== "boolean" || rawBehavior.reuse !== void 0 && typeof rawBehavior.reuse !== "boolean")) return void 0;
|
|
3749
|
+
return Object.freeze({
|
|
3750
|
+
archetype: source.archetype,
|
|
3751
|
+
action: source.action,
|
|
3752
|
+
convention: source.convention,
|
|
3753
|
+
...own(source, "payload") ? { payload: source.payload } : {},
|
|
3754
|
+
...source.handler === void 0 ? {} : { handler: source.handler },
|
|
3755
|
+
...parsedHint === void 0 ? {} : { handlerHint: parsedHint },
|
|
3756
|
+
...rawBehavior === void 0 ? {} : { behavior: Object.freeze({
|
|
3757
|
+
...rawBehavior.focus === void 0 ? {} : { focus: rawBehavior.focus },
|
|
3758
|
+
...rawBehavior.reuse === void 0 ? {} : { reuse: rawBehavior.reuse }
|
|
3759
|
+
}) }
|
|
3800
3760
|
});
|
|
3801
3761
|
}
|
|
3762
|
+
function reject(send, id, error = "invoke rejected") {
|
|
3763
|
+
send({ type: "intent.invoke.result", id, result: { ok: false, error } });
|
|
3764
|
+
}
|
|
3802
3765
|
function createIntentService(options) {
|
|
3803
|
-
if (!options ||
|
|
3804
|
-
throw new Error("createIntentService:
|
|
3766
|
+
if (!options || !options.resolver || typeof options.resolveSender !== "function") {
|
|
3767
|
+
throw new Error("createIntentService: resolver and resolveSender are required");
|
|
3805
3768
|
}
|
|
3806
|
-
const { resolver } = options;
|
|
3807
3769
|
let runtimeContext;
|
|
3808
|
-
let
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
const
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
rejectInvoke(
|
|
3816
|
-
send,
|
|
3817
|
-
id,
|
|
3818
|
-
{
|
|
3819
|
-
archetype: typeof raw.archetype === "string" ? raw.archetype : "",
|
|
3820
|
-
action: typeof raw.action === "string" ? raw.action : "open"
|
|
3821
|
-
},
|
|
3822
|
-
validation.error
|
|
3823
|
-
);
|
|
3824
|
-
return;
|
|
3825
|
-
}
|
|
3826
|
-
const sender = runtimeContext?.resolveDTag(windowId);
|
|
3827
|
-
if (!sender) {
|
|
3828
|
-
rejectInvoke(send, id, validation.request);
|
|
3829
|
-
return;
|
|
3830
|
-
}
|
|
3831
|
-
let pending;
|
|
3770
|
+
let unsubscribe;
|
|
3771
|
+
const { resolver, resolveSender } = options;
|
|
3772
|
+
function invoke2(windowId, message, send) {
|
|
3773
|
+
const envelope = message;
|
|
3774
|
+
const id = typeof envelope.id === "string" ? envelope.id : "";
|
|
3775
|
+
const request = validateRequest(envelope.request);
|
|
3776
|
+
let sender;
|
|
3832
3777
|
try {
|
|
3833
|
-
|
|
3778
|
+
sender = resolveSender(windowId);
|
|
3834
3779
|
} catch {
|
|
3835
|
-
|
|
3836
|
-
return;
|
|
3780
|
+
return reject(send, id);
|
|
3837
3781
|
}
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
id,
|
|
3843
|
-
result: result2
|
|
3844
|
-
});
|
|
3845
|
-
},
|
|
3846
|
-
() => {
|
|
3847
|
-
rejectInvoke(send, id, validation.request);
|
|
3848
|
-
}
|
|
3782
|
+
if (!request || !sender) return reject(send, id, request ? "invoke rejected" : "invalid convention");
|
|
3783
|
+
void Promise.resolve().then(() => resolver.invoke(request, { sender, sourceWindowId: windowId })).then(
|
|
3784
|
+
(result2) => send({ type: "intent.invoke.result", id, result: result2 }),
|
|
3785
|
+
() => reject(send, id)
|
|
3849
3786
|
).catch(() => {
|
|
3850
3787
|
});
|
|
3851
3788
|
}
|
|
3852
|
-
function
|
|
3853
|
-
const
|
|
3854
|
-
const id =
|
|
3855
|
-
if (typeof
|
|
3789
|
+
function availability(message, send) {
|
|
3790
|
+
const envelope = message;
|
|
3791
|
+
const id = typeof envelope.id === "string" ? envelope.id : "";
|
|
3792
|
+
if (typeof envelope.archetype !== "string" || envelope.archetype.length === 0) {
|
|
3856
3793
|
send({ type: "intent.available.result", id, error: "invalid archetype" });
|
|
3857
3794
|
return;
|
|
3858
3795
|
}
|
|
3859
|
-
const archetype =
|
|
3860
|
-
|
|
3861
|
-
() =>
|
|
3862
|
-
send,
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
(availability) => ({ type: "intent.available.result", id, availability })
|
|
3866
|
-
);
|
|
3796
|
+
const archetype = envelope.archetype;
|
|
3797
|
+
void Promise.resolve().then(() => resolver.available(archetype)).then(
|
|
3798
|
+
(value) => send({ type: "intent.available.result", id, availability: value }),
|
|
3799
|
+
() => send({ type: "intent.available.result", id, error: "catalog unavailable" })
|
|
3800
|
+
).catch(() => {
|
|
3801
|
+
});
|
|
3867
3802
|
}
|
|
3868
|
-
function
|
|
3869
|
-
const
|
|
3870
|
-
const id =
|
|
3871
|
-
|
|
3872
|
-
() =>
|
|
3873
|
-
send,
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
(handlers) => ({ type: "intent.handlers.result", id, handlers })
|
|
3877
|
-
);
|
|
3803
|
+
function handlers(message, send) {
|
|
3804
|
+
const envelope = message;
|
|
3805
|
+
const id = typeof envelope.id === "string" ? envelope.id : "";
|
|
3806
|
+
void Promise.resolve().then(() => resolver.handlers()).then(
|
|
3807
|
+
(value) => send({ type: "intent.handlers.result", id, handlers: value }),
|
|
3808
|
+
() => send({ type: "intent.handlers.result", id, error: "catalog unavailable" })
|
|
3809
|
+
).catch(() => {
|
|
3810
|
+
});
|
|
3878
3811
|
}
|
|
3879
3812
|
return {
|
|
3880
3813
|
descriptor: INTENT_DESCRIPTOR,
|
|
3881
3814
|
onRegistered(context) {
|
|
3882
|
-
|
|
3883
|
-
unsubscribeChanged?.();
|
|
3884
|
-
} catch {
|
|
3885
|
-
}
|
|
3815
|
+
unsubscribe?.();
|
|
3886
3816
|
runtimeContext = context;
|
|
3887
|
-
|
|
3817
|
+
unsubscribe = resolver.onChanged?.((item) => {
|
|
3888
3818
|
const current = runtimeContext;
|
|
3889
3819
|
if (!current) return;
|
|
3890
|
-
const message = { type: "intent.changed", availability };
|
|
3891
3820
|
for (const windowId of current.listWindowIds()) {
|
|
3892
|
-
current.sendToEligibleNapplet(windowId,
|
|
3821
|
+
current.sendToEligibleNapplet(windowId, { type: "intent.changed", availability: item });
|
|
3893
3822
|
}
|
|
3894
3823
|
});
|
|
3895
3824
|
},
|
|
3896
3825
|
onUnregistered() {
|
|
3897
|
-
|
|
3898
|
-
|
|
3826
|
+
unsubscribe?.();
|
|
3827
|
+
unsubscribe = void 0;
|
|
3899
3828
|
runtimeContext = void 0;
|
|
3900
|
-
try {
|
|
3901
|
-
unsubscribe?.();
|
|
3902
|
-
} catch {
|
|
3903
|
-
}
|
|
3904
3829
|
},
|
|
3905
3830
|
handleMessage(windowId, message, send) {
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
return;
|
|
3910
|
-
case "intent.available":
|
|
3911
|
-
handleAvailable(message, send);
|
|
3912
|
-
return;
|
|
3913
|
-
case "intent.handlers":
|
|
3914
|
-
handleHandlers(message, send);
|
|
3915
|
-
return;
|
|
3916
|
-
default:
|
|
3917
|
-
return;
|
|
3918
|
-
}
|
|
3831
|
+
if (message.type === "intent.invoke") return invoke2(windowId, message, send);
|
|
3832
|
+
if (message.type === "intent.available") return availability(message, send);
|
|
3833
|
+
if (message.type === "intent.handlers") return handlers(message, send);
|
|
3919
3834
|
}
|
|
3920
3835
|
};
|
|
3921
3836
|
}
|
|
3922
3837
|
|
|
3923
3838
|
// src/catalog-intent-resolver.ts
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
return
|
|
3839
|
+
var CONVENTION2 = /^napplet:([a-z0-9][a-z0-9-]*)\/([a-z0-9][a-z0-9-]*)$/;
|
|
3840
|
+
function rejected(error) {
|
|
3841
|
+
return { ok: false, error };
|
|
3842
|
+
}
|
|
3843
|
+
function candidateFor(entry, archetype, defaultId) {
|
|
3844
|
+
const support = entry.archetypes[archetype];
|
|
3845
|
+
if (!support || support.contracts.length === 0) return void 0;
|
|
3846
|
+
const contracts = support.contracts.map((contract) => Object.freeze({
|
|
3847
|
+
convention: contract.convention,
|
|
3848
|
+
params: Object.freeze([...contract.params])
|
|
3849
|
+
}));
|
|
3850
|
+
const conventions = [...new Set(contracts.map((contract) => contract.convention))];
|
|
3851
|
+
const actions = [...new Set(conventions.map((convention) => CONVENTION2.exec(convention)?.[2]).filter((value) => value !== void 0))];
|
|
3852
|
+
if (actions.length === 0) return void 0;
|
|
3853
|
+
return Object.freeze({
|
|
3854
|
+
id: entry.id,
|
|
3855
|
+
...entry.title === void 0 ? {} : { title: entry.title },
|
|
3856
|
+
actions: Object.freeze(actions),
|
|
3857
|
+
conventions: Object.freeze(conventions),
|
|
3858
|
+
contracts: Object.freeze(contracts),
|
|
3859
|
+
...entry.id === defaultId ? { isDefault: true } : {}
|
|
3860
|
+
});
|
|
3938
3861
|
}
|
|
3939
|
-
function
|
|
3940
|
-
return
|
|
3941
|
-
ok: false,
|
|
3942
|
-
archetype: request.archetype,
|
|
3943
|
-
action: request.action ?? "open",
|
|
3944
|
-
handled: false,
|
|
3945
|
-
error
|
|
3946
|
-
};
|
|
3862
|
+
function candidatesFor(catalog, archetype, defaultId) {
|
|
3863
|
+
return catalog.map((entry) => candidateFor(entry, archetype, defaultId)).filter((candidate) => candidate !== void 0);
|
|
3947
3864
|
}
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
const defaultHandler = options.getDefaultHandler?.(archetype);
|
|
3951
|
-
const candidates = candidatesFor(catalog, archetype, defaultHandler);
|
|
3952
|
-
return {
|
|
3953
|
-
archetype,
|
|
3954
|
-
available: candidates.length > 0,
|
|
3955
|
-
candidates,
|
|
3956
|
-
hasDefault: defaultHandler !== void 0 && candidates.some((candidate) => candidate.dTag === defaultHandler)
|
|
3957
|
-
};
|
|
3865
|
+
function compatibleFor(request, candidates) {
|
|
3866
|
+
return candidates.filter((candidate) => candidate.contracts.some((contract) => contract.convention === request.convention));
|
|
3958
3867
|
}
|
|
3959
|
-
async function
|
|
3960
|
-
if (!options.chooseHandler)
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
if (typeof preference === "string" && preference !== "default" && preference !== "choose") {
|
|
3971
|
-
const candidate = compatible.find((item) => item.dTag === preference);
|
|
3972
|
-
if (!candidate || !options.authorizeExplicitHandler) return { error: "invoke rejected" };
|
|
3973
|
-
let authorized = false;
|
|
3868
|
+
async function choose(options, request, candidates, sender) {
|
|
3869
|
+
if (!options.chooseHandler) return rejected(request.handler === "choose" ? "user cancelled" : "invoke rejected");
|
|
3870
|
+
const id = await options.chooseHandler(request.archetype, candidates, sender);
|
|
3871
|
+
if (id === void 0) return rejected("user cancelled");
|
|
3872
|
+
return candidates.find((candidate) => candidate.id === id) ?? rejected("invoke rejected");
|
|
3873
|
+
}
|
|
3874
|
+
async function select(options, request, candidates, context) {
|
|
3875
|
+
const { sender } = context;
|
|
3876
|
+
if (request.handler && request.handler !== "default" && request.handler !== "choose") {
|
|
3877
|
+
const candidate = candidates.find((item) => item.id === request.handler);
|
|
3878
|
+
if (!candidate || !options.authorizeExplicitHandler) return rejected("invoke rejected");
|
|
3974
3879
|
try {
|
|
3975
|
-
|
|
3976
|
-
sender,
|
|
3977
|
-
preference,
|
|
3978
|
-
request,
|
|
3979
|
-
candidate
|
|
3980
|
-
);
|
|
3880
|
+
return await options.authorizeExplicitHandler(sender, request.handler, request, candidate, context) ? candidate : rejected("invoke rejected");
|
|
3981
3881
|
} catch {
|
|
3982
|
-
return
|
|
3882
|
+
return rejected("invoke rejected");
|
|
3983
3883
|
}
|
|
3984
|
-
return authorized ? { candidate } : { error: "invoke rejected" };
|
|
3985
3884
|
}
|
|
3986
|
-
if (
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3885
|
+
if (request.handler === "choose") return choose(options, request, candidates, sender);
|
|
3886
|
+
const defaultCandidate = candidates.find((candidate) => candidate.isDefault);
|
|
3887
|
+
if (defaultCandidate) return defaultCandidate;
|
|
3888
|
+
if (request.handlerHint && options.resolveHandlerHint) {
|
|
3889
|
+
try {
|
|
3890
|
+
const id = await options.resolveHandlerHint(request.handlerHint, candidates);
|
|
3891
|
+
const candidate = candidates.find((item) => item.id === id);
|
|
3892
|
+
if (candidate) return candidate;
|
|
3893
|
+
} catch {
|
|
3894
|
+
}
|
|
3992
3895
|
}
|
|
3993
|
-
if (
|
|
3994
|
-
|
|
3995
|
-
return chooseCompatible(options, request, compatible, sender);
|
|
3896
|
+
if (candidates.length === 1) return candidates[0];
|
|
3897
|
+
return choose(options, request, candidates, sender);
|
|
3996
3898
|
}
|
|
3997
|
-
async function
|
|
3899
|
+
async function availabilityFor(options, archetype) {
|
|
3998
3900
|
const catalog = await options.loadCatalog();
|
|
3999
|
-
const
|
|
4000
|
-
const candidates = candidatesFor(catalog,
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
if (compatible.length === 0) return reject(request, "unsupported convention");
|
|
4007
|
-
const sender = context.sender;
|
|
4008
|
-
if (typeof sender !== "string" || sender.length === 0) {
|
|
4009
|
-
return reject(request, "invoke rejected");
|
|
4010
|
-
}
|
|
4011
|
-
const selected = await pickHandler(options, request, compatible, sender);
|
|
4012
|
-
if ("error" in selected) return reject(request, selected.error);
|
|
4013
|
-
const convention = request.convention ?? selected.candidate.conventions.find((value) => {
|
|
4014
|
-
const match = /^napplet:[^/?#\s]+\/([^/?#\s]+)$/.exec(value);
|
|
4015
|
-
return match?.[1] === action;
|
|
3901
|
+
const defaultId = options.getDefaultHandler?.(archetype);
|
|
3902
|
+
const candidates = candidatesFor(catalog, archetype, defaultId);
|
|
3903
|
+
return Object.freeze({
|
|
3904
|
+
archetype,
|
|
3905
|
+
available: candidates.length > 0,
|
|
3906
|
+
candidates: Object.freeze(candidates),
|
|
3907
|
+
hasDefault: candidates.some((candidate) => candidate.isDefault)
|
|
4016
3908
|
});
|
|
4017
|
-
|
|
3909
|
+
}
|
|
3910
|
+
async function invoke(options, request, context) {
|
|
3911
|
+
const match = CONVENTION2.exec(request.convention);
|
|
3912
|
+
if (!match || match[1] !== request.archetype || match[2] !== request.action) return rejected("invalid convention");
|
|
3913
|
+
if (!context.sender) return rejected("invoke rejected");
|
|
3914
|
+
const catalog = await options.loadCatalog();
|
|
3915
|
+
const candidates = candidatesFor(catalog, request.archetype, options.getDefaultHandler?.(request.archetype));
|
|
3916
|
+
if (candidates.length === 0) return rejected("no handler");
|
|
3917
|
+
const compatible = compatibleFor(request, candidates);
|
|
3918
|
+
if (compatible.length === 0) return rejected(candidates.some((candidate) => candidate.actions.includes(request.action)) ? "unsupported convention" : "unsupported action");
|
|
3919
|
+
const selected = await select(options, request, compatible, context);
|
|
3920
|
+
if ("ok" in selected) return selected;
|
|
4018
3921
|
const behavior = request.behavior === void 0 ? void 0 : Object.freeze({
|
|
4019
3922
|
...request.behavior.focus === void 0 ? {} : { focus: request.behavior.focus },
|
|
4020
|
-
...request.behavior.newWindow === void 0 ? {} : { newWindow: request.behavior.newWindow },
|
|
4021
3923
|
...request.behavior.reuse === void 0 ? {} : { reuse: request.behavior.reuse }
|
|
4022
3924
|
});
|
|
4023
3925
|
const params = Object.freeze({
|
|
4024
|
-
handler: selected.
|
|
4025
|
-
sender,
|
|
3926
|
+
handler: selected.id,
|
|
3927
|
+
sender: context.sender,
|
|
4026
3928
|
archetype: request.archetype,
|
|
4027
|
-
action,
|
|
4028
|
-
convention,
|
|
3929
|
+
action: request.action,
|
|
3930
|
+
convention: request.convention,
|
|
4029
3931
|
...request.payload === void 0 ? {} : { payload: request.payload },
|
|
4030
|
-
...behavior === void 0 ? {} : { behavior }
|
|
3932
|
+
...behavior === void 0 ? {} : { behavior },
|
|
3933
|
+
...context.sourceWindowId === void 0 ? {} : { sourceWindowId: context.sourceWindowId }
|
|
4031
3934
|
});
|
|
4032
|
-
let target;
|
|
4033
3935
|
try {
|
|
4034
|
-
|
|
3936
|
+
const accepted = options.targets.accept(params);
|
|
3937
|
+
if (!accepted || !(accepted.completion instanceof Promise)) return rejected("invoke rejected");
|
|
3938
|
+
void accepted.completion.catch(() => {
|
|
3939
|
+
});
|
|
4035
3940
|
} catch {
|
|
4036
|
-
return
|
|
3941
|
+
return rejected("invoke rejected");
|
|
4037
3942
|
}
|
|
4038
|
-
|
|
4039
|
-
return reject(request, "invoke failed");
|
|
4040
|
-
}
|
|
4041
|
-
return {
|
|
4042
|
-
ok: true,
|
|
4043
|
-
archetype: request.archetype,
|
|
4044
|
-
action,
|
|
4045
|
-
handled: true,
|
|
4046
|
-
handler: selected.candidate.dTag,
|
|
4047
|
-
windowId: target.windowId,
|
|
4048
|
-
convention
|
|
4049
|
-
};
|
|
3943
|
+
return { ok: true, archetype: request.archetype, action: request.action, convention: request.convention, handler: selected.id };
|
|
4050
3944
|
}
|
|
4051
3945
|
function createCatalogIntentResolver(options) {
|
|
4052
|
-
if (!options || typeof options.loadCatalog !== "function")
|
|
4053
|
-
|
|
4054
|
-
}
|
|
4055
|
-
if (!options.targets || typeof options.targets.dispatch !== "function") {
|
|
4056
|
-
throw new Error("createCatalogIntentResolver: options.targets is required");
|
|
4057
|
-
}
|
|
3946
|
+
if (!options || typeof options.loadCatalog !== "function") throw new Error("createCatalogIntentResolver: options.loadCatalog is required");
|
|
3947
|
+
if (!options.targets || typeof options.targets.accept !== "function") throw new Error("createCatalogIntentResolver: options.targets is required");
|
|
4058
3948
|
const listeners = /* @__PURE__ */ new Set();
|
|
4059
|
-
const availabilityFor = (archetype) => availabilityForCatalog(options, archetype);
|
|
4060
|
-
async function handlers() {
|
|
4061
|
-
const catalog = await options.loadCatalog();
|
|
4062
|
-
const archetypes = /* @__PURE__ */ new Set();
|
|
4063
|
-
for (const entry of catalog) {
|
|
4064
|
-
for (const slug of Object.keys(entry.archetypes)) archetypes.add(slug);
|
|
4065
|
-
}
|
|
4066
|
-
return Promise.all([...archetypes].map((archetype) => availabilityFor(archetype)));
|
|
4067
|
-
}
|
|
4068
3949
|
return {
|
|
4069
|
-
invoke: (request, context) =>
|
|
4070
|
-
available: availabilityFor,
|
|
4071
|
-
handlers
|
|
3950
|
+
invoke: (request, context) => invoke(options, request, context),
|
|
3951
|
+
available: (archetype) => availabilityFor(options, archetype),
|
|
3952
|
+
async handlers() {
|
|
3953
|
+
const catalog = await options.loadCatalog();
|
|
3954
|
+
const roles = /* @__PURE__ */ new Set();
|
|
3955
|
+
for (const entry of catalog) for (const role of Object.keys(entry.archetypes)) roles.add(role);
|
|
3956
|
+
return Promise.all([...roles].map((role) => availabilityFor(options, role)));
|
|
3957
|
+
},
|
|
4072
3958
|
onChanged(listener) {
|
|
4073
3959
|
listeners.add(listener);
|
|
4074
3960
|
return () => listeners.delete(listener);
|
|
4075
3961
|
},
|
|
4076
3962
|
notifyChanged(archetype) {
|
|
4077
|
-
|
|
4078
|
-
void availabilityFor(archetype).then((availability) => {
|
|
3963
|
+
void availabilityFor(options, archetype).then((availability) => {
|
|
4079
3964
|
for (const listener of listeners) listener(availability);
|
|
4080
3965
|
});
|
|
4081
3966
|
}
|
|
@@ -4091,21 +3976,24 @@ function actionFromConvention(convention) {
|
|
|
4091
3976
|
return match[2];
|
|
4092
3977
|
}
|
|
4093
3978
|
function manifestToIntentCatalogEntry(manifest) {
|
|
4094
|
-
const archetypes =
|
|
4095
|
-
for (const { slug, convention } of manifest.archetypes) {
|
|
3979
|
+
const archetypes = /* @__PURE__ */ Object.create(null);
|
|
3980
|
+
for (const { slug, convention, params } of manifest.archetypes) {
|
|
4096
3981
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
|
|
4097
3982
|
throw new TypeError("manifest archetype slug is invalid");
|
|
4098
3983
|
}
|
|
4099
|
-
|
|
3984
|
+
actionFromConvention(convention);
|
|
3985
|
+
if (!convention.startsWith(`napplet:${slug}/`)) {
|
|
3986
|
+
throw new TypeError("manifest archetype must match its convention role");
|
|
3987
|
+
}
|
|
4100
3988
|
const support = archetypes[slug] ??= {
|
|
4101
|
-
|
|
4102
|
-
conventions: []
|
|
3989
|
+
contracts: []
|
|
4103
3990
|
};
|
|
4104
|
-
if (!support.
|
|
4105
|
-
|
|
3991
|
+
if (!support.contracts.some((contract) => contract.convention === convention)) {
|
|
3992
|
+
support.contracts.push({ convention, params: [...params] });
|
|
3993
|
+
}
|
|
4106
3994
|
}
|
|
4107
3995
|
return {
|
|
4108
|
-
|
|
3996
|
+
id: manifest.catalogId,
|
|
4109
3997
|
...manifest.title === void 0 ? {} : { title: manifest.title },
|
|
4110
3998
|
archetypes
|
|
4111
3999
|
};
|
|
@@ -4153,7 +4041,7 @@ function createCvmService(options) {
|
|
|
4153
4041
|
const m = msg;
|
|
4154
4042
|
const id = m.id ?? "";
|
|
4155
4043
|
void transport.discover(m.query).then((servers) => send({ type: "cvm.discover.result", id, servers })).catch(
|
|
4156
|
-
(err2) => send({ type: "cvm.discover.result", id, servers: [], error:
|
|
4044
|
+
(err2) => send({ type: "cvm.discover.result", id, servers: [], error: toErrorMessage4(err2) })
|
|
4157
4045
|
);
|
|
4158
4046
|
}
|
|
4159
4047
|
function handleRequest(windowId, msg, send) {
|
|
@@ -4169,7 +4057,7 @@ function createCvmService(options) {
|
|
|
4169
4057
|
}
|
|
4170
4058
|
openSession(windowId, m.server, send);
|
|
4171
4059
|
void transport.request(m.server, m.message, m.options).then((message) => send({ type: "cvm.request.result", id, message })).catch(
|
|
4172
|
-
(err2) => send({ type: "cvm.request.result", id, error:
|
|
4060
|
+
(err2) => send({ type: "cvm.request.result", id, error: toErrorMessage4(err2) })
|
|
4173
4061
|
);
|
|
4174
4062
|
}
|
|
4175
4063
|
function handleClose(windowId, msg, send) {
|
|
@@ -4180,7 +4068,7 @@ function createCvmService(options) {
|
|
|
4180
4068
|
return;
|
|
4181
4069
|
}
|
|
4182
4070
|
closeSession(windowId, m.server.pubkey);
|
|
4183
|
-
void transport.close(m.server).then(() => send({ type: "cvm.close.result", id })).catch((err2) => send({ type: "cvm.close.result", id, error:
|
|
4071
|
+
void transport.close(m.server).then(() => send({ type: "cvm.close.result", id })).catch((err2) => send({ type: "cvm.close.result", id, error: toErrorMessage4(err2) }));
|
|
4184
4072
|
}
|
|
4185
4073
|
return {
|
|
4186
4074
|
descriptor: CVM_DESCRIPTOR,
|
|
@@ -4218,7 +4106,7 @@ function createCvmService(options) {
|
|
|
4218
4106
|
}
|
|
4219
4107
|
};
|
|
4220
4108
|
}
|
|
4221
|
-
function
|
|
4109
|
+
function toErrorMessage4(err2) {
|
|
4222
4110
|
if (err2 instanceof Error) return err2.message;
|
|
4223
4111
|
if (typeof err2 === "string") return err2;
|
|
4224
4112
|
return "cvm request failed";
|
|
@@ -4414,15 +4302,15 @@ function createSerialService(options = {}) {
|
|
|
4414
4302
|
const currentWindow = (windowId) => {
|
|
4415
4303
|
const existing = windows.get(windowId);
|
|
4416
4304
|
if (existing) return existing;
|
|
4417
|
-
const
|
|
4305
|
+
const record2 = {
|
|
4418
4306
|
connections: /* @__PURE__ */ new Map(),
|
|
4419
4307
|
pendingConnections: /* @__PURE__ */ new Set()
|
|
4420
4308
|
};
|
|
4421
|
-
windows.set(windowId,
|
|
4422
|
-
return
|
|
4309
|
+
windows.set(windowId, record2);
|
|
4310
|
+
return record2;
|
|
4423
4311
|
};
|
|
4424
|
-
const emit = (windowId,
|
|
4425
|
-
if (!connection || windows.get(windowId) !==
|
|
4312
|
+
const emit = (windowId, record2, connection, send, event) => {
|
|
4313
|
+
if (!connection || windows.get(windowId) !== record2 || connection.state === "closed") return;
|
|
4426
4314
|
if (connection.state === "opening") {
|
|
4427
4315
|
connection.bufferedEvents.push(event);
|
|
4428
4316
|
return;
|
|
@@ -4433,8 +4321,8 @@ function createSerialService(options = {}) {
|
|
|
4433
4321
|
descriptor: SERIAL_DESCRIPTOR,
|
|
4434
4322
|
handleMessage(windowId, message, send) {
|
|
4435
4323
|
const id = message.id ?? "";
|
|
4436
|
-
const
|
|
4437
|
-
const isCurrent = () => windows.get(windowId) ===
|
|
4324
|
+
const record2 = currentWindow(windowId);
|
|
4325
|
+
const isCurrent = () => windows.get(windowId) === record2;
|
|
4438
4326
|
const currentSend = (outbound) => {
|
|
4439
4327
|
if (isCurrent()) send(outbound);
|
|
4440
4328
|
};
|
|
@@ -4445,13 +4333,13 @@ function createSerialService(options = {}) {
|
|
|
4445
4333
|
}
|
|
4446
4334
|
const serialMessage = message;
|
|
4447
4335
|
const connection = { state: "opening", bufferedEvents: [] };
|
|
4448
|
-
|
|
4449
|
-
const context = createContext(windowId, (event) => emit(windowId,
|
|
4336
|
+
record2.pendingConnections.add(connection);
|
|
4337
|
+
const context = createContext(windowId, (event) => emit(windowId, record2, connection, currentSend, event));
|
|
4450
4338
|
let pending;
|
|
4451
4339
|
try {
|
|
4452
4340
|
pending = Promise.resolve(options.open(serialMessage.request, context));
|
|
4453
4341
|
} catch (error) {
|
|
4454
|
-
|
|
4342
|
+
record2.pendingConnections.delete(connection);
|
|
4455
4343
|
connection.state = "closed";
|
|
4456
4344
|
currentSend({
|
|
4457
4345
|
type: "serial.open.result",
|
|
@@ -4461,10 +4349,10 @@ function createSerialService(options = {}) {
|
|
|
4461
4349
|
return;
|
|
4462
4350
|
}
|
|
4463
4351
|
void pending.then((result2) => {
|
|
4464
|
-
|
|
4352
|
+
record2.pendingConnections.delete(connection);
|
|
4465
4353
|
if (!isCurrent() || connection.state === "closed") return;
|
|
4466
4354
|
connection.state = "open";
|
|
4467
|
-
|
|
4355
|
+
record2.connections.set(result2.session.id, connection);
|
|
4468
4356
|
currentSend({ type: "serial.open.result", id, session: result2.session });
|
|
4469
4357
|
if (!isCurrent() || connection.state !== "open") return;
|
|
4470
4358
|
for (const event of connection.bufferedEvents) {
|
|
@@ -4473,7 +4361,7 @@ function createSerialService(options = {}) {
|
|
|
4473
4361
|
}
|
|
4474
4362
|
connection.bufferedEvents.length = 0;
|
|
4475
4363
|
}).catch((error) => {
|
|
4476
|
-
|
|
4364
|
+
record2.pendingConnections.delete(connection);
|
|
4477
4365
|
connection.state = "closed";
|
|
4478
4366
|
currentSend({
|
|
4479
4367
|
type: "serial.open.result",
|
|
@@ -4491,8 +4379,8 @@ function createSerialService(options = {}) {
|
|
|
4491
4379
|
const serialMessage = message;
|
|
4492
4380
|
const context = createContext(windowId, (event) => emit(
|
|
4493
4381
|
windowId,
|
|
4494
|
-
|
|
4495
|
-
|
|
4382
|
+
record2,
|
|
4383
|
+
record2.connections.get(serialMessage.sessionId),
|
|
4496
4384
|
currentSend,
|
|
4497
4385
|
event
|
|
4498
4386
|
));
|
|
@@ -4510,14 +4398,14 @@ function createSerialService(options = {}) {
|
|
|
4510
4398
|
return;
|
|
4511
4399
|
}
|
|
4512
4400
|
const serialMessage = message;
|
|
4513
|
-
const connection =
|
|
4401
|
+
const connection = record2.connections.get(serialMessage.sessionId);
|
|
4514
4402
|
if (connection) {
|
|
4515
4403
|
connection.state = "closed";
|
|
4516
|
-
|
|
4404
|
+
record2.connections.delete(serialMessage.sessionId);
|
|
4517
4405
|
}
|
|
4518
4406
|
const context = createContext(windowId, (event) => emit(
|
|
4519
4407
|
windowId,
|
|
4520
|
-
|
|
4408
|
+
record2,
|
|
4521
4409
|
connection,
|
|
4522
4410
|
currentSend,
|
|
4523
4411
|
event
|
|
@@ -4537,12 +4425,12 @@ function createSerialService(options = {}) {
|
|
|
4537
4425
|
});
|
|
4538
4426
|
},
|
|
4539
4427
|
onWindowDestroyed(windowId) {
|
|
4540
|
-
const
|
|
4541
|
-
if (
|
|
4542
|
-
for (const connection of
|
|
4543
|
-
for (const connection of
|
|
4544
|
-
|
|
4545
|
-
|
|
4428
|
+
const record2 = windows.get(windowId);
|
|
4429
|
+
if (record2) {
|
|
4430
|
+
for (const connection of record2.connections.values()) connection.state = "closed";
|
|
4431
|
+
for (const connection of record2.pendingConnections) connection.state = "closed";
|
|
4432
|
+
record2.connections.clear();
|
|
4433
|
+
record2.pendingConnections.clear();
|
|
4546
4434
|
windows.delete(windowId);
|
|
4547
4435
|
}
|
|
4548
4436
|
options.destroyWindow?.(windowId);
|
|
@@ -5611,13 +5499,13 @@ function createCordnRelayCoordinatorClient(options) {
|
|
|
5611
5499
|
const cursor = (cursors.get(gid) ?? 0) + 1;
|
|
5612
5500
|
cursors.set(gid, cursor);
|
|
5613
5501
|
const at = nowSeconds3();
|
|
5614
|
-
const
|
|
5502
|
+
const record2 = { cursor, gid, msg_64: input.msg_64, at };
|
|
5615
5503
|
const event = finalizeEvent2(
|
|
5616
5504
|
{
|
|
5617
5505
|
kind,
|
|
5618
5506
|
created_at: at,
|
|
5619
5507
|
tags: [["g", gid], ["p", ownerPubkey]],
|
|
5620
|
-
content: JSON.stringify(
|
|
5508
|
+
content: JSON.stringify(record2)
|
|
5621
5509
|
},
|
|
5622
5510
|
options.ownerSecretKey
|
|
5623
5511
|
);
|
|
@@ -5695,8 +5583,8 @@ function createCordnDmAdapter(options) {
|
|
|
5695
5583
|
if (options.client) return options.client.messages(query);
|
|
5696
5584
|
const gid = query.conversationId.startsWith("group:") ? query.conversationId.slice("group:".length) : query.conversationId;
|
|
5697
5585
|
const fetched = await options.coordinator.FetchGroupMessages({ gid });
|
|
5698
|
-
for (const
|
|
5699
|
-
(options.decodeMessage ?? defaultDecodeMessage)(
|
|
5586
|
+
for (const record2 of fetched.messages) store.upsertMessage(
|
|
5587
|
+
(options.decodeMessage ?? defaultDecodeMessage)(record2, ownerPubkey),
|
|
5700
5588
|
[ownerPubkey ?? "", gid]
|
|
5701
5589
|
);
|
|
5702
5590
|
return store.messages(query);
|
|
@@ -5705,8 +5593,8 @@ function createCordnDmAdapter(options) {
|
|
|
5705
5593
|
if (options.client) return options.client.send(request);
|
|
5706
5594
|
const encoded = (options.encodeMessage ?? ((req, pk) => defaultEncodeMessage(req, pk, options.defaultGroupId)))(request, ownerPubkey);
|
|
5707
5595
|
const posted = await options.coordinator.PostGroupMessage({ msg_64: encoded.msg_64 });
|
|
5708
|
-
const
|
|
5709
|
-
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(
|
|
5596
|
+
const record2 = { ...posted, msg_64: encoded.msg_64 };
|
|
5597
|
+
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(record2, ownerPubkey), [ownerPubkey ?? "", encoded.gid]);
|
|
5710
5598
|
return { ok: true, message: { ...message, status: "sent" } };
|
|
5711
5599
|
},
|
|
5712
5600
|
async subscribe(request, onMessage) {
|
|
@@ -5716,17 +5604,17 @@ function createCordnDmAdapter(options) {
|
|
|
5716
5604
|
const gid = conversationId.startsWith("group:") ? conversationId.slice("group:".length) : conversationId;
|
|
5717
5605
|
const fetched = await options.coordinator.FetchGroupMessages({ gid });
|
|
5718
5606
|
let after = 0;
|
|
5719
|
-
for (const
|
|
5720
|
-
after = Math.max(after,
|
|
5721
|
-
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(
|
|
5607
|
+
for (const record2 of fetched.messages) {
|
|
5608
|
+
after = Math.max(after, record2.cursor);
|
|
5609
|
+
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(record2, ownerPubkey), [ownerPubkey ?? "", gid]);
|
|
5722
5610
|
onMessage(message);
|
|
5723
5611
|
}
|
|
5724
5612
|
const subscription = await options.coordinator.SubscribeGroupMessages({ gid, after });
|
|
5725
5613
|
const subscriptionId = `dm-cordn-${++cordnSubCounter}`;
|
|
5726
5614
|
live.set(subscriptionId, { abort: () => subscription.abort("dm.unsubscribe"), conversationId });
|
|
5727
5615
|
void (async () => {
|
|
5728
|
-
for await (const
|
|
5729
|
-
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(
|
|
5616
|
+
for await (const record2 of subscription.stream) {
|
|
5617
|
+
const message = store.upsertMessage((options.decodeMessage ?? defaultDecodeMessage)(record2, ownerPubkey), [ownerPubkey ?? "", gid]);
|
|
5730
5618
|
onMessage(message);
|
|
5731
5619
|
}
|
|
5732
5620
|
})();
|