@kehto/paja 0.8.0 → 0.10.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 +68 -2
- package/dist/browser-host.js +2509 -1050
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-NFJCS5PG.js → chunk-EOCGC7A2.js} +363 -10
- package/dist/chunk-EOCGC7A2.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +198 -6
- package/dist/index.js +11 -1
- package/package.json +11 -11
- package/dist/chunk-NFJCS5PG.js.map +0 -1
|
@@ -697,12 +697,12 @@ async function resolvePajaPointer(value, options = {}) {
|
|
|
697
697
|
const pointer = decodePajaPointer(value);
|
|
698
698
|
const relays = uniqueRelayUrls([...pointer.relays, ...options.relays ?? []]);
|
|
699
699
|
if (relays.length === 0) {
|
|
700
|
-
throw new Error("Pointer
|
|
700
|
+
throw new Error("Pointer has no relay hints or enabled configured live relays.");
|
|
701
701
|
}
|
|
702
702
|
const pool = options.pool ?? new SimplePool();
|
|
703
703
|
const ownsPool = options.pool === void 0;
|
|
704
704
|
try {
|
|
705
|
-
const event = await resolvePointerEvent(pointer, pool, relays, options.maxWaitMs
|
|
705
|
+
const event = await resolvePointerEvent(pointer, pool, relays, normalizeMaxWaitMs(options.maxWaitMs));
|
|
706
706
|
const blossomServers = [...options.blossomServers ?? []];
|
|
707
707
|
const resolved = await resolveNapplet({
|
|
708
708
|
event,
|
|
@@ -731,7 +731,26 @@ async function resolvePajaPointer(value, options = {}) {
|
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
733
|
function injectPajaRuntimeCsp(html, origins) {
|
|
734
|
-
const
|
|
734
|
+
const grantedOrigins = [...new Set(origins)].sort();
|
|
735
|
+
const connectSrc = grantedOrigins.length > 0 ? `connect-src ${grantedOrigins.join(" ")}` : "connect-src 'none'";
|
|
736
|
+
const value = [
|
|
737
|
+
"default-src 'none'",
|
|
738
|
+
"script-src 'unsafe-inline'",
|
|
739
|
+
"style-src 'unsafe-inline'",
|
|
740
|
+
"img-src data: blob:",
|
|
741
|
+
"font-src data:",
|
|
742
|
+
connectSrc,
|
|
743
|
+
"worker-src 'none'",
|
|
744
|
+
"child-src 'none'",
|
|
745
|
+
"frame-src 'none'",
|
|
746
|
+
"media-src 'none'",
|
|
747
|
+
"object-src 'none'",
|
|
748
|
+
"manifest-src 'none'",
|
|
749
|
+
"prefetch-src 'none'",
|
|
750
|
+
"base-uri 'none'",
|
|
751
|
+
"form-action 'none'",
|
|
752
|
+
"frame-ancestors 'self'"
|
|
753
|
+
].join("; ");
|
|
735
754
|
const meta = `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute2(value)}">`;
|
|
736
755
|
if (/<head[^>]*>/i.test(html)) {
|
|
737
756
|
return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);
|
|
@@ -743,19 +762,96 @@ function injectPajaRuntimeCsp(html, origins) {
|
|
|
743
762
|
}
|
|
744
763
|
async function resolvePointerEvent(pointer, pool, relays, maxWaitMs) {
|
|
745
764
|
const filter = pointer.type === "naddr" ? addressableFilter(pointer) : eventFilter(pointer);
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
label: "kehto-paja-runtime"
|
|
749
|
-
});
|
|
750
|
-
const event = events.filter((candidate) => matchesPointer(pointer, candidate)).sort((a, b) => b.created_at - a.created_at)[0];
|
|
765
|
+
const result = await queryPointerRelays(pool, relays, filter, maxWaitMs);
|
|
766
|
+
const event = result.events.filter((candidate) => matchesPointer(pointer, candidate)).sort((a, b) => b.created_at - a.created_at)[0];
|
|
751
767
|
if (!event) {
|
|
752
|
-
|
|
768
|
+
if (result.timedOut) {
|
|
769
|
+
throw new Error(
|
|
770
|
+
`Relay resolution timed out after ${maxWaitMs}ms for ${pointer.type} pointer across ${relays.length} relays before complete EOSE.`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
const failures = relayFailureReasons(result.reasons);
|
|
774
|
+
if (result.error || failures.length > 0) {
|
|
775
|
+
const detail = result.error instanceof Error ? result.error.message : result.error === void 0 ? failures.join("; ") : String(result.error);
|
|
776
|
+
throw new Error(`Relay query failed for ${pointer.type} pointer before complete EOSE: ${detail}`);
|
|
777
|
+
}
|
|
778
|
+
throw new Error(
|
|
779
|
+
`All ${relays.length} relays reached EOSE without a matching ${pointer.type} napplet manifest event.`
|
|
780
|
+
);
|
|
753
781
|
}
|
|
754
782
|
if (!isNappletManifestKind(event.kind)) {
|
|
755
783
|
throw new Error(`Pointer resolved kind ${event.kind}; expected ${formatNappletManifestKinds()}.`);
|
|
756
784
|
}
|
|
757
785
|
return event;
|
|
758
786
|
}
|
|
787
|
+
function queryPointerRelays(pool, relays, filter, maxWaitMs) {
|
|
788
|
+
if (pool.subscribeManyEose) {
|
|
789
|
+
return queryPointerRelaySubscription(pool, relays, filter, maxWaitMs);
|
|
790
|
+
}
|
|
791
|
+
return queryPointerRelaySync(pool, relays, filter, maxWaitMs);
|
|
792
|
+
}
|
|
793
|
+
function queryPointerRelaySubscription(pool, relays, filter, maxWaitMs) {
|
|
794
|
+
return new Promise((resolve2) => {
|
|
795
|
+
const events = [];
|
|
796
|
+
let settled = false;
|
|
797
|
+
let subscription;
|
|
798
|
+
const finish = (result) => {
|
|
799
|
+
if (settled) return;
|
|
800
|
+
settled = true;
|
|
801
|
+
clearTimeout(deadline);
|
|
802
|
+
resolve2({ events, ...result });
|
|
803
|
+
};
|
|
804
|
+
const deadline = setTimeout(() => {
|
|
805
|
+
finish({ reasons: [], timedOut: true });
|
|
806
|
+
void subscription?.close("Paja pointer relay deadline exceeded");
|
|
807
|
+
}, maxWaitMs);
|
|
808
|
+
try {
|
|
809
|
+
subscription = pool.subscribeManyEose([...relays], filter, {
|
|
810
|
+
maxWait: maxWaitMs,
|
|
811
|
+
label: "kehto-paja-runtime",
|
|
812
|
+
onevent(event) {
|
|
813
|
+
events.push(event);
|
|
814
|
+
},
|
|
815
|
+
onclose(reasons) {
|
|
816
|
+
finish({ reasons, timedOut: false });
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
} catch (error) {
|
|
820
|
+
finish({ reasons: [], timedOut: false, error });
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
function queryPointerRelaySync(pool, relays, filter, maxWaitMs) {
|
|
825
|
+
return new Promise((resolve2) => {
|
|
826
|
+
let settled = false;
|
|
827
|
+
const finish = (result) => {
|
|
828
|
+
if (settled) return;
|
|
829
|
+
settled = true;
|
|
830
|
+
clearTimeout(deadline);
|
|
831
|
+
resolve2(result);
|
|
832
|
+
};
|
|
833
|
+
const deadline = setTimeout(() => {
|
|
834
|
+
finish({ events: [], reasons: [], timedOut: true });
|
|
835
|
+
}, maxWaitMs);
|
|
836
|
+
void pool.querySync([...relays], filter, {
|
|
837
|
+
maxWait: maxWaitMs,
|
|
838
|
+
label: "kehto-paja-runtime"
|
|
839
|
+
}).then(
|
|
840
|
+
(events) => finish({ events, reasons: [], timedOut: false }),
|
|
841
|
+
(error) => finish({ events: [], reasons: [], timedOut: false, error })
|
|
842
|
+
);
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
function relayFailureReasons(reasons) {
|
|
846
|
+
return [...new Set(reasons.map((reason) => reason.trim()).filter((reason) => reason.length > 0 && reason !== "closed automatically on eose").map((reason) => reason.slice(0, 160)))].slice(0, 3);
|
|
847
|
+
}
|
|
848
|
+
function normalizeMaxWaitMs(value) {
|
|
849
|
+
if (value === void 0) return 5e3;
|
|
850
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
851
|
+
throw new Error("Pointer relay deadline must be a positive number of milliseconds.");
|
|
852
|
+
}
|
|
853
|
+
return Math.floor(value);
|
|
854
|
+
}
|
|
759
855
|
function addressableFilter(pointer) {
|
|
760
856
|
if (pointer.kind !== NAPPLET_KIND_NAMED) {
|
|
761
857
|
throw new Error(`naddr kind ${pointer.kind} is not a named NIP-5D napplet manifest kind.`);
|
|
@@ -824,6 +920,7 @@ var PAJA_UPSTREAM_WEB_DOMAINS = [
|
|
|
824
920
|
"count",
|
|
825
921
|
"cvm",
|
|
826
922
|
"dm",
|
|
923
|
+
"fs",
|
|
827
924
|
"identity",
|
|
828
925
|
PAJA_LEGACY_COMPATIBILITY_DOMAIN,
|
|
829
926
|
"inc",
|
|
@@ -937,9 +1034,251 @@ function defaultSleep(ms) {
|
|
|
937
1034
|
});
|
|
938
1035
|
}
|
|
939
1036
|
|
|
1037
|
+
// src/installed-napplet-catalog.ts
|
|
1038
|
+
import { manifestToIntentCatalogEntry } from "@kehto/services";
|
|
1039
|
+
function matchesInstalledNappletRecord(record, target) {
|
|
1040
|
+
return target.dTag === record.dTag && target.aggregateHash === record.aggregateHash;
|
|
1041
|
+
}
|
|
1042
|
+
var InstalledNappletCatalog = class {
|
|
1043
|
+
records = /* @__PURE__ */ new Map();
|
|
1044
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1045
|
+
/** Insert or replace a record from an already resolver-verified pointer. */
|
|
1046
|
+
install(resolved) {
|
|
1047
|
+
const record = freezeRecord({
|
|
1048
|
+
dTag: resolved.dTag,
|
|
1049
|
+
aggregateHash: resolved.aggregateHash,
|
|
1050
|
+
pointer: copyPointer(resolved.pointer),
|
|
1051
|
+
...resolved.manifest.title === void 0 ? {} : { title: resolved.manifest.title },
|
|
1052
|
+
requires: [...resolved.manifest.requires],
|
|
1053
|
+
archetypes: resolved.manifest.archetypes.map((archetype) => ({
|
|
1054
|
+
slug: archetype.slug,
|
|
1055
|
+
convention: archetype.convention
|
|
1056
|
+
}))
|
|
1057
|
+
});
|
|
1058
|
+
this.records.set(record.dTag, record);
|
|
1059
|
+
this.notify(record.dTag);
|
|
1060
|
+
return record;
|
|
1061
|
+
}
|
|
1062
|
+
/** Remove an artifact explicitly; frame teardown never calls this method. */
|
|
1063
|
+
remove(dTag) {
|
|
1064
|
+
const removed = this.records.delete(dTag);
|
|
1065
|
+
if (removed) this.notify(dTag);
|
|
1066
|
+
return removed;
|
|
1067
|
+
}
|
|
1068
|
+
/** Return whether a verified installation exists for a d-tag. */
|
|
1069
|
+
has(dTag) {
|
|
1070
|
+
return this.records.has(dTag);
|
|
1071
|
+
}
|
|
1072
|
+
/** Return immutable serializable installed-artifact facts. */
|
|
1073
|
+
installed() {
|
|
1074
|
+
return [...this.records.values()];
|
|
1075
|
+
}
|
|
1076
|
+
/** Return a verified record by d-tag. */
|
|
1077
|
+
get(dTag) {
|
|
1078
|
+
return this.records.get(dTag);
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Atomically confirm that a resolved target still belongs to the exact record
|
|
1082
|
+
* selected before an async operation. The record object is the catalog version
|
|
1083
|
+
* token, so even a same-identity replacement cannot pass this check.
|
|
1084
|
+
*/
|
|
1085
|
+
validateCurrent(selected, target) {
|
|
1086
|
+
if (this.records.get(selected.dTag) !== selected) return null;
|
|
1087
|
+
return matchesInstalledNappletRecord(selected, target) ? selected : null;
|
|
1088
|
+
}
|
|
1089
|
+
/** Return exact handler candidates derived only from installed manifests. */
|
|
1090
|
+
intentCatalog() {
|
|
1091
|
+
return this.installed().filter((record) => record.requires.includes("inc")).map((record) => manifestToIntentCatalogEntry({
|
|
1092
|
+
dTag: record.dTag,
|
|
1093
|
+
...record.title === void 0 ? {} : { title: record.title },
|
|
1094
|
+
archetypes: record.archetypes.map((archetype) => ({
|
|
1095
|
+
slug: archetype.slug,
|
|
1096
|
+
convention: archetype.convention
|
|
1097
|
+
}))
|
|
1098
|
+
}));
|
|
1099
|
+
}
|
|
1100
|
+
/** Subscribe to explicit install and artifact-removal changes. */
|
|
1101
|
+
onChanged(listener) {
|
|
1102
|
+
this.listeners.add(listener);
|
|
1103
|
+
return () => this.listeners.delete(listener);
|
|
1104
|
+
}
|
|
1105
|
+
notify(dTag) {
|
|
1106
|
+
for (const listener of this.listeners) listener(dTag);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
function copyPointer(pointer) {
|
|
1110
|
+
if (pointer.type === "naddr") {
|
|
1111
|
+
return Object.freeze({
|
|
1112
|
+
type: "naddr",
|
|
1113
|
+
value: pointer.value,
|
|
1114
|
+
identifier: pointer.identifier,
|
|
1115
|
+
pubkey: pointer.pubkey,
|
|
1116
|
+
kind: pointer.kind,
|
|
1117
|
+
relays: Object.freeze([...pointer.relays])
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
return Object.freeze({
|
|
1121
|
+
type: "nevent",
|
|
1122
|
+
value: pointer.value,
|
|
1123
|
+
id: pointer.id,
|
|
1124
|
+
...pointer.author === void 0 ? {} : { author: pointer.author },
|
|
1125
|
+
...pointer.kind === void 0 ? {} : { kind: pointer.kind },
|
|
1126
|
+
relays: Object.freeze([...pointer.relays])
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
function freezeRecord(record) {
|
|
1130
|
+
return Object.freeze({
|
|
1131
|
+
...record,
|
|
1132
|
+
requires: Object.freeze([...record.requires]),
|
|
1133
|
+
archetypes: Object.freeze(record.archetypes.map((archetype) => Object.freeze({ ...archetype })))
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// src/browser-intent-controller.ts
|
|
1138
|
+
var MAX_INTENT_DELIVERY_ATTEMPTS = 10;
|
|
1139
|
+
var BrowserIntentController = class {
|
|
1140
|
+
constructor(options) {
|
|
1141
|
+
this.options = options;
|
|
1142
|
+
this.maxAttempts = normalizeAttempts(options.maxAttempts);
|
|
1143
|
+
}
|
|
1144
|
+
options;
|
|
1145
|
+
maxAttempts;
|
|
1146
|
+
async dispatch(params) {
|
|
1147
|
+
const dispatch = freezeDispatch(params);
|
|
1148
|
+
let reason = "no-current-target";
|
|
1149
|
+
for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {
|
|
1150
|
+
let generation;
|
|
1151
|
+
try {
|
|
1152
|
+
generation = await this.options.openOrReuse(dispatch, attempt);
|
|
1153
|
+
} catch {
|
|
1154
|
+
reason = "open-failed";
|
|
1155
|
+
continue;
|
|
1156
|
+
}
|
|
1157
|
+
if (!generation) {
|
|
1158
|
+
reason = "open-failed";
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
try {
|
|
1162
|
+
await this.options.waitForReady(generation);
|
|
1163
|
+
} catch {
|
|
1164
|
+
reason = "ready-failed";
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1167
|
+
if (!await this.options.isCurrent(generation)) {
|
|
1168
|
+
reason = "no-current-target";
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
try {
|
|
1172
|
+
await this.options.send(generation, dispatch);
|
|
1173
|
+
const windowId = this.options.getWindowId(generation);
|
|
1174
|
+
if (!windowId) throw new Error("intent target window is unavailable");
|
|
1175
|
+
return { windowId };
|
|
1176
|
+
} catch {
|
|
1177
|
+
this.options.onTerminal?.(dispatch, "send-failed");
|
|
1178
|
+
throw new Error("intent target send failed");
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
this.options.onTerminal?.(dispatch, reason);
|
|
1182
|
+
throw new Error(`intent target ${reason}`);
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
function normalizeAttempts(value) {
|
|
1186
|
+
if (value === void 0) return 2;
|
|
1187
|
+
if (!Number.isFinite(value)) throw new TypeError("maxAttempts must be finite");
|
|
1188
|
+
return Math.min(MAX_INTENT_DELIVERY_ATTEMPTS, Math.max(1, Math.floor(value)));
|
|
1189
|
+
}
|
|
1190
|
+
function freezeDispatch(params) {
|
|
1191
|
+
if (!params || typeof params.handler !== "string" || params.handler.length === 0) {
|
|
1192
|
+
throw new TypeError("Intent dispatch requires a handler");
|
|
1193
|
+
}
|
|
1194
|
+
if (typeof params.sender !== "string" || params.sender.length === 0 || typeof params.archetype !== "string" || params.archetype.length === 0 || typeof params.action !== "string" || params.action.length === 0 || typeof params.convention !== "string" || params.convention.length === 0) {
|
|
1195
|
+
throw new TypeError("Intent dispatch requires canonical routing fields");
|
|
1196
|
+
}
|
|
1197
|
+
const payload = freezeValue(params.payload);
|
|
1198
|
+
const behavior = params.behavior === void 0 ? void 0 : freezeValue({ ...params.behavior });
|
|
1199
|
+
return Object.freeze({
|
|
1200
|
+
handler: params.handler,
|
|
1201
|
+
sender: params.sender,
|
|
1202
|
+
archetype: params.archetype,
|
|
1203
|
+
action: params.action,
|
|
1204
|
+
convention: params.convention,
|
|
1205
|
+
...params.payload === void 0 ? {} : { payload },
|
|
1206
|
+
...behavior === void 0 ? {} : { behavior }
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
function freezeValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
1210
|
+
if (typeof value !== "object" || value === null) return value;
|
|
1211
|
+
const existing = seen.get(value);
|
|
1212
|
+
if (existing !== void 0) return existing;
|
|
1213
|
+
if (Array.isArray(value)) {
|
|
1214
|
+
const copy2 = [];
|
|
1215
|
+
seen.set(value, copy2);
|
|
1216
|
+
for (const item of value) copy2.push(freezeValue(item, seen));
|
|
1217
|
+
return Object.freeze(copy2);
|
|
1218
|
+
}
|
|
1219
|
+
const copy = {};
|
|
1220
|
+
seen.set(value, copy);
|
|
1221
|
+
for (const [key, item] of Object.entries(value)) copy[key] = freezeValue(item, seen);
|
|
1222
|
+
return Object.freeze(copy);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
940
1225
|
// src/server.ts
|
|
941
1226
|
import { createServer } from "http";
|
|
942
1227
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1228
|
+
|
|
1229
|
+
// src/target-cors.ts
|
|
1230
|
+
var PAJA_TARGET_CORS_HINT = "Paja sandboxes the napplet frame without allow-same-origin, so its assets are requested with `Origin: null`. Allow that origin in the napplet dev server, e.g. Vite `server: { cors: { origin: '*' } }`.";
|
|
1231
|
+
function classifyTargetCors(targetUrl, allowOrigin) {
|
|
1232
|
+
const value = allowOrigin?.trim() ?? null;
|
|
1233
|
+
if (value === "*" || value === "null") {
|
|
1234
|
+
return {
|
|
1235
|
+
status: "allowed",
|
|
1236
|
+
targetUrl,
|
|
1237
|
+
allowOrigin: value,
|
|
1238
|
+
detail: `Target allows the sandboxed frame's null origin (access-control-allow-origin: ${value}).`,
|
|
1239
|
+
hint: null
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
if (value === null || value === "") {
|
|
1243
|
+
return {
|
|
1244
|
+
status: "blocked",
|
|
1245
|
+
targetUrl,
|
|
1246
|
+
allowOrigin: null,
|
|
1247
|
+
detail: "Target sent no access-control-allow-origin for an Origin: null request.",
|
|
1248
|
+
hint: PAJA_TARGET_CORS_HINT
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
return {
|
|
1252
|
+
status: "blocked",
|
|
1253
|
+
targetUrl,
|
|
1254
|
+
allowOrigin: value,
|
|
1255
|
+
detail: `Target only allows origin "${value}", not the sandboxed frame's null origin.`,
|
|
1256
|
+
hint: PAJA_TARGET_CORS_HINT
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
var defaultTargetCorsFetch = (input, init) => fetch(input, init);
|
|
1260
|
+
async function probeTargetCors(targetUrl, fetchImpl = defaultTargetCorsFetch) {
|
|
1261
|
+
try {
|
|
1262
|
+
const response = await fetchImpl(targetUrl, {
|
|
1263
|
+
method: "GET",
|
|
1264
|
+
headers: {
|
|
1265
|
+
origin: "null",
|
|
1266
|
+
accept: "text/html, application/xhtml+xml;q=0.9, */*;q=0.8"
|
|
1267
|
+
}
|
|
1268
|
+
});
|
|
1269
|
+
return classifyTargetCors(targetUrl, response.headers.get("access-control-allow-origin"));
|
|
1270
|
+
} catch (error) {
|
|
1271
|
+
return {
|
|
1272
|
+
status: "unreachable",
|
|
1273
|
+
targetUrl,
|
|
1274
|
+
allowOrigin: null,
|
|
1275
|
+
detail: `Target CORS probe failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1276
|
+
hint: "Confirm the napplet dev server is running and --target-url points at it."
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// src/server.ts
|
|
943
1282
|
async function startPajaServer(input) {
|
|
944
1283
|
const rawOptions = resolvePajaRawOptions(input.options);
|
|
945
1284
|
const options = normalizePajaOptions(rawOptions);
|
|
@@ -975,6 +1314,15 @@ async function startPajaServer(input) {
|
|
|
975
1314
|
response.end(targetHtml);
|
|
976
1315
|
return;
|
|
977
1316
|
}
|
|
1317
|
+
if (requestUrl === "/__kehto/target-cors.json") {
|
|
1318
|
+
const diagnostic = await probeTargetCors(hostConfig.target.url);
|
|
1319
|
+
response.writeHead(200, {
|
|
1320
|
+
"cache-control": "no-store",
|
|
1321
|
+
"content-type": "application/json; charset=utf-8"
|
|
1322
|
+
});
|
|
1323
|
+
response.end(JSON.stringify(diagnostic));
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
978
1326
|
if (requestUrl === "/__kehto/browser-host.js") {
|
|
979
1327
|
const browserScript = readBrowserHostScript();
|
|
980
1328
|
response.writeHead(200, { "content-type": "text/javascript; charset=utf-8" });
|
|
@@ -1104,6 +1452,11 @@ export {
|
|
|
1104
1452
|
getMissingServices,
|
|
1105
1453
|
ReadinessError,
|
|
1106
1454
|
waitForTargetUrl,
|
|
1455
|
+
InstalledNappletCatalog,
|
|
1456
|
+
BrowserIntentController,
|
|
1457
|
+
PAJA_TARGET_CORS_HINT,
|
|
1458
|
+
classifyTargetCors,
|
|
1459
|
+
probeTargetCors,
|
|
1107
1460
|
startPajaServer
|
|
1108
1461
|
};
|
|
1109
|
-
//# sourceMappingURL=chunk-
|
|
1462
|
+
//# sourceMappingURL=chunk-EOCGC7A2.js.map
|