@tappify/extension-sdk 2.0.0 → 2.1.0-beta.1
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 +208 -0
- package/dist/chunk-2CY5HVY7.mjs +59 -0
- package/dist/chunk-2CY5HVY7.mjs.map +1 -0
- package/dist/{chunk-2DBSVKAU.cjs → chunk-6HETNZJY.cjs} +1 -1
- package/dist/chunk-6HETNZJY.cjs.map +1 -0
- package/dist/{chunk-PYJMJF44.cjs → chunk-7YKH4LZN.cjs} +9 -2
- package/dist/chunk-7YKH4LZN.cjs.map +1 -0
- package/dist/{chunk-RMUWRESK.cjs → chunk-A74HCO6T.cjs} +31 -18
- package/dist/chunk-A74HCO6T.cjs.map +1 -0
- package/dist/chunk-BPCGXXMD.cjs +781 -0
- package/dist/chunk-BPCGXXMD.cjs.map +1 -0
- package/dist/chunk-EB5XWQAU.cjs +132 -0
- package/dist/chunk-EB5XWQAU.cjs.map +1 -0
- package/dist/{chunk-5AAPD5WV.cjs → chunk-GAUZYBXE.cjs} +11 -11
- package/dist/chunk-GAUZYBXE.cjs.map +1 -0
- package/dist/chunk-J5LGTIGS.mjs +10 -0
- package/dist/chunk-J5LGTIGS.mjs.map +1 -0
- package/dist/{chunk-ZT35X7KL.mjs → chunk-KZ5NGFUP.mjs} +22 -9
- package/dist/chunk-KZ5NGFUP.mjs.map +1 -0
- package/dist/chunk-NN263PGQ.cjs +70 -0
- package/dist/chunk-NN263PGQ.cjs.map +1 -0
- package/dist/{chunk-3YWVYA42.cjs → chunk-O357OJXL.cjs} +14 -18
- package/dist/chunk-O357OJXL.cjs.map +1 -0
- package/dist/chunk-ONJMPO3P.cjs +59 -0
- package/dist/chunk-ONJMPO3P.cjs.map +1 -0
- package/dist/{chunk-OPPYEA7F.cjs → chunk-PRCZMOLD.cjs} +3 -3
- package/dist/chunk-PRCZMOLD.cjs.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +10 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/{chunk-QHM7XNRK.mjs → chunk-QA5AL3VZ.mjs} +2 -2
- package/dist/{chunk-QHM7XNRK.mjs.map → chunk-QA5AL3VZ.mjs.map} +1 -1
- package/dist/chunk-QJMZRV7A.mjs +132 -0
- package/dist/chunk-QJMZRV7A.mjs.map +1 -0
- package/dist/{chunk-CSTYBKZC.mjs → chunk-QXD7WVKK.mjs} +1 -1
- package/dist/chunk-QXD7WVKK.mjs.map +1 -0
- package/dist/{chunk-4C5Z3CIK.mjs → chunk-RBIQT75L.mjs} +2 -2
- package/dist/chunk-RBIQT75L.mjs.map +1 -0
- package/dist/{chunk-MNDVYPEP.mjs → chunk-SGCYEEXD.mjs} +9 -2
- package/dist/chunk-SGCYEEXD.mjs.map +1 -0
- package/dist/{chunk-BDCX6LRQ.mjs → chunk-SGEYDV3K.mjs} +3 -3
- package/dist/chunk-SGEYDV3K.mjs.map +1 -0
- package/dist/{chunk-IGK2AP6J.mjs → chunk-SLGOHIBL.mjs} +13 -17
- package/dist/chunk-SLGOHIBL.mjs.map +1 -0
- package/dist/chunk-SWG7CNTZ.mjs +781 -0
- package/dist/chunk-SWG7CNTZ.mjs.map +1 -0
- package/dist/{chunk-7KIKOH5H.cjs → chunk-VV7ELNRW.cjs} +3 -3
- package/dist/chunk-VV7ELNRW.cjs.map +1 -0
- package/dist/chunk-Z43DPNZ6.mjs +70 -0
- package/dist/chunk-Z43DPNZ6.mjs.map +1 -0
- package/dist/client-CV1qzQgx.d.cts +25 -0
- package/dist/client-CnlSHDWE.d.ts +25 -0
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.d.cts +40 -7
- package/dist/codegen.d.ts +40 -7
- package/dist/codegen.mjs.map +1 -1
- package/dist/{constants-DJ_KgZpN.d.cts → constants-BAimnqOK.d.cts} +41 -8
- package/dist/{constants-DJ_KgZpN.d.ts → constants-BAimnqOK.d.ts} +41 -8
- package/dist/{context-Ml7k_V14.d.ts → context-Cr93B05o.d.ts} +5 -4
- package/dist/{context-Dt6xh_5t.d.cts → context-DJ3REtdT.d.cts} +5 -4
- package/dist/{errors-COsBh7kd.d.cts → errors-Cqh0wrqt.d.cts} +3 -2
- package/dist/{errors-COsBh7kd.d.ts → errors-Cqh0wrqt.d.ts} +3 -2
- package/dist/host.cjs +5 -4
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +5 -5
- package/dist/host.d.ts +5 -5
- package/dist/host.mjs +4 -3
- package/dist/host.mjs.map +1 -1
- package/dist/index.cjs +9 -656
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -627
- package/dist/index.d.ts +69 -627
- package/dist/index.mjs +5 -652
- package/dist/index.mjs.map +1 -1
- package/dist/manifest.cjs +138 -85
- package/dist/manifest.cjs.map +1 -1
- package/dist/manifest.d.cts +93 -12
- package/dist/manifest.d.ts +93 -12
- package/dist/manifest.mjs +125 -72
- package/dist/manifest.mjs.map +1 -1
- package/dist/server.cjs +15 -66
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/server.mjs +10 -61
- package/dist/server.mjs.map +1 -1
- package/dist/testing/index.cjs +73 -750
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +30 -11
- package/dist/testing/index.d.ts +30 -11
- package/dist/testing/index.mjs +89 -766
- package/dist/testing/index.mjs.map +1 -1
- package/dist/testing/jest.cjs +6 -5
- package/dist/testing/jest.cjs.map +1 -1
- package/dist/testing/jest.mjs +3 -2
- package/dist/testing/jest.mjs.map +1 -1
- package/dist/testing/vitest.cjs +6 -5
- package/dist/testing/vitest.cjs.map +1 -1
- package/dist/testing/vitest.d.cts +10 -0
- package/dist/testing/vitest.d.ts +10 -0
- package/dist/testing/vitest.mjs +3 -2
- package/dist/testing/vitest.mjs.map +1 -1
- package/dist/{types-DrpQSv_2.d.cts → types-BYGcp5pZ.d.ts} +4 -3
- package/dist/{types-DDAGLpov.d.ts → types-I1JOZyI_.d.cts} +4 -3
- package/dist/ui/styles.css +740 -0
- package/dist/ui.cjs +1018 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.cts +231 -0
- package/dist/ui.d.ts +231 -0
- package/dist/ui.mjs +1018 -0
- package/dist/ui.mjs.map +1 -0
- package/dist/vite-preview-bootstrap.cjs +66 -0
- package/dist/vite-preview-bootstrap.cjs.map +1 -0
- package/dist/vite-preview-bootstrap.d.cts +15 -0
- package/dist/vite-preview-bootstrap.d.ts +15 -0
- package/dist/vite-preview-bootstrap.mjs +66 -0
- package/dist/vite-preview-bootstrap.mjs.map +1 -0
- package/dist/vite-preview.cjs +876 -0
- package/dist/vite-preview.cjs.map +1 -0
- package/dist/vite-preview.d.cts +9 -0
- package/dist/vite-preview.d.ts +9 -0
- package/dist/vite-preview.mjs +876 -0
- package/dist/vite-preview.mjs.map +1 -0
- package/dist/vite.cjs +316 -59
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +51 -8
- package/dist/vite.d.ts +51 -8
- package/dist/vite.mjs +308 -53
- package/dist/vite.mjs.map +1 -1
- package/dist/work-events-DB3WR468.d.ts +547 -0
- package/dist/work-events-Dxe7Djdy.d.cts +547 -0
- package/package.json +19 -2
- package/schema/extension-v2.json +432 -121
- package/dist/chunk-2DBSVKAU.cjs.map +0 -1
- package/dist/chunk-3YWVYA42.cjs.map +0 -1
- package/dist/chunk-4C5Z3CIK.mjs.map +0 -1
- package/dist/chunk-5AAPD5WV.cjs.map +0 -1
- package/dist/chunk-7KIKOH5H.cjs.map +0 -1
- package/dist/chunk-BDCX6LRQ.mjs.map +0 -1
- package/dist/chunk-CSTYBKZC.mjs.map +0 -1
- package/dist/chunk-IGK2AP6J.mjs.map +0 -1
- package/dist/chunk-MNDVYPEP.mjs.map +0 -1
- package/dist/chunk-OPPYEA7F.cjs.map +0 -1
- package/dist/chunk-PYJMJF44.cjs.map +0 -1
- package/dist/chunk-RMUWRESK.cjs.map +0 -1
- package/dist/chunk-ZT35X7KL.mjs.map +0 -1
- package/dist/handler-CZIlZ5vu.d.ts +0 -227
- package/dist/handler-kU9Jf36K.d.cts +0 -227
- package/dist/styles.css +0 -367
package/dist/vite.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/vite/plugin.ts
|
|
2
2
|
import { federation } from "@module-federation/vite";
|
|
3
3
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4
|
-
import { resolve as
|
|
4
|
+
import { resolve as resolve3, sep as sep2 } from "path";
|
|
5
5
|
|
|
6
6
|
// src/client/errors.ts
|
|
7
7
|
var TAP_ERROR_CODES = [
|
|
@@ -143,6 +143,13 @@ var SCOPES = [
|
|
|
143
143
|
requiresSecurityReview: false,
|
|
144
144
|
requiresJustification: false
|
|
145
145
|
},
|
|
146
|
+
{
|
|
147
|
+
key: "review.threads:read",
|
|
148
|
+
label: "Read Review threads",
|
|
149
|
+
description: "Review threads, comments, screenshot descriptors, build context and safe device context",
|
|
150
|
+
requiresSecurityReview: false,
|
|
151
|
+
requiresJustification: false
|
|
152
|
+
},
|
|
146
153
|
{
|
|
147
154
|
key: "crashes:read",
|
|
148
155
|
label: "Read crash data",
|
|
@@ -216,7 +223,7 @@ var SCOPES = [
|
|
|
216
223
|
{
|
|
217
224
|
key: "work:sync",
|
|
218
225
|
label: "Sync work items",
|
|
219
|
-
description: "
|
|
226
|
+
description: "Sync comments and status on created work items",
|
|
220
227
|
requiresSecurityReview: false,
|
|
221
228
|
requiresJustification: true
|
|
222
229
|
},
|
|
@@ -664,7 +671,7 @@ var aiContribution = z.object({
|
|
|
664
671
|
).optional()
|
|
665
672
|
}).strict();
|
|
666
673
|
var statusNames = (stage) => z.array(z.string()).describe(`Your own status names that mean ${stage}.`);
|
|
667
|
-
var
|
|
674
|
+
var legacyWorkContribution = z.object({
|
|
668
675
|
kind: z.enum(["tracker", "docs", "chat"]).describe("What kind of destination this is."),
|
|
669
676
|
container: z.object({
|
|
670
677
|
label: z.string().min(1).max(60).describe(
|
|
@@ -699,6 +706,55 @@ var workContribution = z.object({
|
|
|
699
706
|
"Whether items are created as the owner who asked (`user`) or as the install itself."
|
|
700
707
|
)
|
|
701
708
|
}).strict();
|
|
709
|
+
var workDirection = z.enum([
|
|
710
|
+
"none",
|
|
711
|
+
"to_provider",
|
|
712
|
+
"from_provider",
|
|
713
|
+
"two-way"
|
|
714
|
+
]);
|
|
715
|
+
var workAuth = z.discriminatedUnion("method", [
|
|
716
|
+
z.object({
|
|
717
|
+
method: z.literal("oauth"),
|
|
718
|
+
provider: z.string().min(1).describe("The OAuth provider identifier."),
|
|
719
|
+
scopes: z.array(z.string()).describe("The scopes requested from the provider.")
|
|
720
|
+
}).strict(),
|
|
721
|
+
z.object({
|
|
722
|
+
method: z.literal("api_key"),
|
|
723
|
+
fields: z.array(credentialField).max(20)
|
|
724
|
+
}).strict()
|
|
725
|
+
]);
|
|
726
|
+
var currentWorkContribution = legacyWorkContribution.extend({
|
|
727
|
+
container: legacyWorkContribution.shape.container.describe(
|
|
728
|
+
"Deprecated. Resolve containers dynamically with describe_container."
|
|
729
|
+
).optional(),
|
|
730
|
+
fields: legacyWorkContribution.shape.fields.describe("Deprecated. Resolve fields dynamically with describe_container.").optional(),
|
|
731
|
+
comments: z.union([
|
|
732
|
+
z.enum(["two-way", "none"]).describe("Deprecated. Declare a comments capability object."),
|
|
733
|
+
z.object({
|
|
734
|
+
direction: workDirection,
|
|
735
|
+
supportsEdits: z.literal(false),
|
|
736
|
+
supportsDeletes: z.literal(false)
|
|
737
|
+
}).strict()
|
|
738
|
+
]),
|
|
739
|
+
status: z.object({
|
|
740
|
+
direction: workDirection,
|
|
741
|
+
webhook: z.string().regex(DOMAIN_EVENT).optional(),
|
|
742
|
+
map: z.object({
|
|
743
|
+
open: statusNames("not started"),
|
|
744
|
+
in_progress: statusNames("under way"),
|
|
745
|
+
done: statusNames("finished")
|
|
746
|
+
}).strict().describe(
|
|
747
|
+
"Deprecated. Resolve statuses dynamically with describe_container."
|
|
748
|
+
).optional()
|
|
749
|
+
}).strict().optional(),
|
|
750
|
+
auth: workAuth.describe("How owners authenticate the work destination.")
|
|
751
|
+
});
|
|
752
|
+
var workContribution = z.union([
|
|
753
|
+
currentWorkContribution,
|
|
754
|
+
legacyWorkContribution.describe(
|
|
755
|
+
"Deprecated SDK v2 work declaration. Migrate to work capabilities and auth."
|
|
756
|
+
)
|
|
757
|
+
]);
|
|
702
758
|
var listing = z.object({
|
|
703
759
|
longDescription: z.string().min(1).max(5e3).describe("The body of your listing page, in markdown.").optional(),
|
|
704
760
|
screenshots: z.array(z.string().min(1)).min(1, "A listing shows 1 to 6 screenshots.").max(6, "A listing shows 1 to 6 screenshots.").describe(
|
|
@@ -790,7 +846,7 @@ var manifestObject = z.object({
|
|
|
790
846
|
"What this extension offers the assistant: tools, mentions, actions, knowledge, skills, prompts and context providers."
|
|
791
847
|
).optional(),
|
|
792
848
|
work: workContribution.describe(
|
|
793
|
-
"The work destination this extension creates issues, pages or messages in. Needs
|
|
849
|
+
"The work destination this extension creates issues, pages or messages in. Needs `review.threads:read` and `work:create`; active comment or status sync also needs `work:sync`."
|
|
794
850
|
).optional()
|
|
795
851
|
}).strict().describe(
|
|
796
852
|
"What this extension adds to the host. At most 20 UI contributions in total, and a page, tab, widget, row action, marker or settings panel needs the `ui:render` scope."
|
|
@@ -1011,16 +1067,36 @@ var manifestSchema = manifestObject.superRefine((manifest, ctx) => {
|
|
|
1011
1067
|
}
|
|
1012
1068
|
}
|
|
1013
1069
|
if (contributes.work) {
|
|
1070
|
+
const work = contributes.work;
|
|
1071
|
+
const legacy = isLegacyWork(work);
|
|
1072
|
+
if (!legacy || !granted.has("reviews:read")) {
|
|
1073
|
+
requireScope(
|
|
1074
|
+
"review.threads:read",
|
|
1075
|
+
["scopes"],
|
|
1076
|
+
"the work destination reads Review threads."
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1014
1079
|
requireScope(
|
|
1015
1080
|
"work:create",
|
|
1016
1081
|
["scopes"],
|
|
1017
1082
|
"the work destination creates items."
|
|
1018
1083
|
);
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1084
|
+
const comments = typeof work.comments === "string" ? work.comments : work.comments.direction;
|
|
1085
|
+
const status = work.status ? "direction" in work.status ? work.status.direction : "from_provider" : "none";
|
|
1086
|
+
if (comments !== "none" || status !== "none") {
|
|
1087
|
+
requireScope(
|
|
1088
|
+
"work:sync",
|
|
1089
|
+
["scopes"],
|
|
1090
|
+
"the work destination syncs comments or status."
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
if (work.identity === "user") {
|
|
1094
|
+
ctx.addIssue({
|
|
1095
|
+
code: "custom",
|
|
1096
|
+
path: ["contributes", "work", "identity"],
|
|
1097
|
+
message: 'Per-user work identity is not supported. Set identity to "install".'
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1024
1100
|
}
|
|
1025
1101
|
const needsServer = contributes.connector !== void 0 || (contributes.webhooks?.length ?? 0) > 0 || ai !== void 0 || contributes.work !== void 0 || manifest.server?.procedures !== void 0;
|
|
1026
1102
|
if (needsServer && !manifest.server?.baseUrl) {
|
|
@@ -1095,10 +1171,176 @@ function validateManifest(value) {
|
|
|
1095
1171
|
}));
|
|
1096
1172
|
return { ok: false, issues };
|
|
1097
1173
|
}
|
|
1174
|
+
function isLegacyWork(work) {
|
|
1175
|
+
return !("auth" in work);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/vite/preview/plugin.ts
|
|
1179
|
+
import { randomUUID } from "crypto";
|
|
1180
|
+
import { isAbsolute, relative, resolve } from "path";
|
|
1181
|
+
import { normalizePath } from "vite";
|
|
1182
|
+
var PREVIEW_CLIENT_ID = "virtual:tappify-preview/client";
|
|
1183
|
+
var PREVIEW_MANIFEST_ID = "virtual:tappify-preview/manifest";
|
|
1184
|
+
var PREVIEW_REMOTE_ID = "virtual:tappify-preview/remote";
|
|
1185
|
+
var PREVIEW_REMOTE_ENV = "TAPPIFY_PREVIEW_REMOTE";
|
|
1186
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1187
|
+
var VIRTUAL_IDS = /* @__PURE__ */ new Set([
|
|
1188
|
+
PREVIEW_CLIENT_ID,
|
|
1189
|
+
PREVIEW_MANIFEST_ID,
|
|
1190
|
+
PREVIEW_REMOTE_ID
|
|
1191
|
+
]);
|
|
1192
|
+
function previewRemote(remote, port) {
|
|
1193
|
+
if (remote === void 0 || remote.trim() === "") {
|
|
1194
|
+
return { ok: true, url: `http://localhost:${String(port)}/remoteEntry.js` };
|
|
1195
|
+
}
|
|
1196
|
+
let parsed;
|
|
1197
|
+
try {
|
|
1198
|
+
parsed = new URL(remote);
|
|
1199
|
+
} catch {
|
|
1200
|
+
return { ok: false, message: "The preview remote is not a valid URL." };
|
|
1201
|
+
}
|
|
1202
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && LOOPBACK_HOSTS.has(parsed.hostname))) {
|
|
1203
|
+
return {
|
|
1204
|
+
ok: false,
|
|
1205
|
+
message: "A preview remote must use HTTPS or loopback HTTP."
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
return { ok: true, url: parsed.toString() };
|
|
1209
|
+
}
|
|
1210
|
+
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1211
|
+
function messageDocument(title2, messages) {
|
|
1212
|
+
return `<!doctype html>
|
|
1213
|
+
<html lang="en">
|
|
1214
|
+
<head>
|
|
1215
|
+
<meta charset="UTF-8" />
|
|
1216
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1217
|
+
<title>${escapeHtml(title2)} \xB7 Tappify local preview</title>
|
|
1218
|
+
<style>body{margin:0;min-height:100vh;display:grid;place-content:center;padding:32px;box-sizing:border-box;background:#f4f5ef;color:#142012;font-family:Inter,ui-sans-serif,system-ui,sans-serif}main{max-width:720px;padding:28px;border:1px solid #d8ddcf;border-radius:12px;background:#fff;box-shadow:0 12px 36px rgb(20 32 18 / 9%)}h1{font-size:22px;margin:0 0 14px}ul{margin:0;padding-left:22px;color:#4d5849}li+li{margin-top:8px}</style>
|
|
1219
|
+
</head>
|
|
1220
|
+
<body><main><h1>${escapeHtml(title2)}</h1><ul>${messages.map((message) => `<li>${escapeHtml(message)}</li>`).join("")}</ul></main></body>
|
|
1221
|
+
</html>`;
|
|
1222
|
+
}
|
|
1223
|
+
function previewDocument(manifest, remote) {
|
|
1224
|
+
if (!manifest.ok) {
|
|
1225
|
+
return messageDocument(
|
|
1226
|
+
"Manifest is invalid",
|
|
1227
|
+
manifest.issues.map((issue) => `${issue.path}: ${issue.message}`)
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
if (!remote.ok)
|
|
1231
|
+
return messageDocument("Preview remote was refused", [remote.message]);
|
|
1232
|
+
const icon = manifest.manifest.icon.replace(/^\.\//, "");
|
|
1233
|
+
return `<!doctype html>
|
|
1234
|
+
<html lang="en">
|
|
1235
|
+
<head>
|
|
1236
|
+
<meta charset="UTF-8" />
|
|
1237
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1238
|
+
<link rel="icon" href="/${escapeHtml(icon)}" />
|
|
1239
|
+
<title>${escapeHtml(manifest.manifest.name)} \xB7 Tappify local preview</title>
|
|
1240
|
+
</head>
|
|
1241
|
+
<body>
|
|
1242
|
+
<div id="tappify-preview-root"></div>
|
|
1243
|
+
<script type="module" src="/@id/${PREVIEW_CLIENT_ID}"></script>
|
|
1244
|
+
</body>
|
|
1245
|
+
</html>`;
|
|
1246
|
+
}
|
|
1247
|
+
var moduleSource = (value) => `export default ${JSON.stringify(value)};`;
|
|
1248
|
+
function optimizedReactUrl(root, cacheDir, cacheGeneration) {
|
|
1249
|
+
const depsCacheDir = normalizePath(resolve(cacheDir, "deps"));
|
|
1250
|
+
const relativeCacheDir = normalizePath(relative(root, depsCacheDir));
|
|
1251
|
+
const prefix = isAbsolute(relativeCacheDir) || relativeCacheDir.startsWith("../") ? `/@fs/${depsCacheDir.replace(/^\/+/, "")}` : `/${relativeCacheDir}`;
|
|
1252
|
+
return `${prefix}/react.js?tappify=${encodeURIComponent(cacheGeneration)}`;
|
|
1253
|
+
}
|
|
1254
|
+
function createPreviewPlugins(options) {
|
|
1255
|
+
const remote = previewRemote(options.remote, options.port);
|
|
1256
|
+
const cacheGeneration = randomUUID();
|
|
1257
|
+
let reactUrl = optimizedReactUrl(
|
|
1258
|
+
resolve(options.manifestFile, ".."),
|
|
1259
|
+
resolve(options.manifestFile, "../node_modules/.vite"),
|
|
1260
|
+
cacheGeneration
|
|
1261
|
+
);
|
|
1262
|
+
const preview = {
|
|
1263
|
+
name: "tappify:preview",
|
|
1264
|
+
apply: "serve",
|
|
1265
|
+
config() {
|
|
1266
|
+
return {
|
|
1267
|
+
optimizeDeps: {
|
|
1268
|
+
exclude: ["@tappify/extension-sdk/vite/preview/bootstrap"]
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
},
|
|
1272
|
+
configResolved(config) {
|
|
1273
|
+
reactUrl = optimizedReactUrl(
|
|
1274
|
+
config.root,
|
|
1275
|
+
config.cacheDir,
|
|
1276
|
+
cacheGeneration
|
|
1277
|
+
);
|
|
1278
|
+
},
|
|
1279
|
+
resolveId(id) {
|
|
1280
|
+
if (VIRTUAL_IDS.has(id)) return `\0${id}`;
|
|
1281
|
+
if (id.startsWith("\0") && VIRTUAL_IDS.has(id.slice(1))) return id;
|
|
1282
|
+
return null;
|
|
1283
|
+
},
|
|
1284
|
+
load(id) {
|
|
1285
|
+
if (id === `\0${PREVIEW_MANIFEST_ID}`) {
|
|
1286
|
+
return moduleSource(options.loadManifest());
|
|
1287
|
+
}
|
|
1288
|
+
if (id === `\0${PREVIEW_REMOTE_ID}`) return moduleSource(remote);
|
|
1289
|
+
if (id !== `\0${PREVIEW_CLIENT_ID}`) return null;
|
|
1290
|
+
return [
|
|
1291
|
+
`import { startLocalPreview } from '@tappify/extension-sdk/vite/preview/bootstrap';`,
|
|
1292
|
+
`import manifest from '${PREVIEW_MANIFEST_ID}';`,
|
|
1293
|
+
`import remote from '${PREVIEW_REMOTE_ID}';`,
|
|
1294
|
+
`const mount = document.getElementById('tappify-preview-root');`,
|
|
1295
|
+
`if (mount && manifest.ok && remote.ok) void startLocalPreview({ manifest: manifest.manifest, remote: remote.url, reactUrl: ${JSON.stringify(reactUrl)}, mount });`
|
|
1296
|
+
].join("\n");
|
|
1297
|
+
},
|
|
1298
|
+
configureServer(server) {
|
|
1299
|
+
server.middlewares.use((request, response, next) => {
|
|
1300
|
+
const path = request.url?.split("?", 1)[0];
|
|
1301
|
+
if (path !== "/" && path !== "/index.html") return next();
|
|
1302
|
+
void server.transformIndexHtml(
|
|
1303
|
+
path,
|
|
1304
|
+
previewDocument(options.loadManifest(), remote)
|
|
1305
|
+
).then((html) => {
|
|
1306
|
+
response.statusCode = 200;
|
|
1307
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1308
|
+
response.end(html);
|
|
1309
|
+
}).catch(next);
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
const dev = {
|
|
1314
|
+
name: "tappify:dev",
|
|
1315
|
+
apply: "serve",
|
|
1316
|
+
config() {
|
|
1317
|
+
return {
|
|
1318
|
+
server: {
|
|
1319
|
+
host: "127.0.0.1",
|
|
1320
|
+
port: options.port,
|
|
1321
|
+
strictPort: true,
|
|
1322
|
+
cors: { origin: true },
|
|
1323
|
+
origin: `http://localhost:${String(options.port)}`
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
},
|
|
1327
|
+
configureServer(server) {
|
|
1328
|
+
server.watcher.add(options.manifestFile);
|
|
1329
|
+
},
|
|
1330
|
+
async hotUpdate(context) {
|
|
1331
|
+
if (this.environment.name !== "client") return;
|
|
1332
|
+
if (context.file !== options.manifestFile) return;
|
|
1333
|
+
const manifest = options.loadManifest();
|
|
1334
|
+
await options.onManifestChange?.(manifest);
|
|
1335
|
+
context.server.ws.send({ type: "full-reload", path: "*" });
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
return [preview, dev];
|
|
1339
|
+
}
|
|
1098
1340
|
|
|
1099
1341
|
// src/vite/styles.ts
|
|
1100
1342
|
import { existsSync, readFileSync } from "fs";
|
|
1101
|
-
import { dirname, extname, resolve, sep } from "path";
|
|
1343
|
+
import { dirname, extname, resolve as resolve2, sep } from "path";
|
|
1102
1344
|
var IMPORT_PATTERN = /(?:^|\n)\s*(?:import|export)(?:[^'"]*?from\s*)?\s*['"]([^'"]+)['"]/g;
|
|
1103
1345
|
var IMPORT_SPECIFIER_PATTERN = /((?:^|\n)\s*(?:import|export)(?:[^'"]*?from\s*)?\s*['"])([^'"]+)(['"])/g;
|
|
1104
1346
|
var BLOCK_COMMENT_PATTERN = /\/\*[\s\S]*?\*\//g;
|
|
@@ -1111,14 +1353,14 @@ function isPlainStylesheet(specifier) {
|
|
|
1111
1353
|
return specifier.endsWith(".css") && !specifier.endsWith(".module.css");
|
|
1112
1354
|
}
|
|
1113
1355
|
function resolveSource(specifier, importer) {
|
|
1114
|
-
const base =
|
|
1356
|
+
const base = resolve2(dirname(importer), specifier);
|
|
1115
1357
|
if (extname(base) !== "" && existsSync(base)) return base;
|
|
1116
1358
|
for (const extension of SOURCE_EXTENSIONS) {
|
|
1117
1359
|
const candidate = `${base}${extension}`;
|
|
1118
1360
|
if (existsSync(candidate)) return candidate;
|
|
1119
1361
|
}
|
|
1120
1362
|
for (const extension of SOURCE_EXTENSIONS) {
|
|
1121
|
-
const candidate =
|
|
1363
|
+
const candidate = resolve2(base, `index${extension}`);
|
|
1122
1364
|
if (existsSync(candidate)) return candidate;
|
|
1123
1365
|
}
|
|
1124
1366
|
return null;
|
|
@@ -1140,7 +1382,7 @@ function collectEntryStyles(entryAbsolutePath, root) {
|
|
|
1140
1382
|
while (match !== null) {
|
|
1141
1383
|
const specifier = match[1];
|
|
1142
1384
|
if (specifier.endsWith(".css")) {
|
|
1143
|
-
const value = specifier.startsWith(".") ?
|
|
1385
|
+
const value = specifier.startsWith(".") ? resolve2(dirname(file), specifier) : specifier;
|
|
1144
1386
|
if (!seenStyles.has(value)) {
|
|
1145
1387
|
seenStyles.add(value);
|
|
1146
1388
|
styles.push(value);
|
|
@@ -1173,38 +1415,52 @@ var DEFAULT_PORT = 5273;
|
|
|
1173
1415
|
var SOURCE_FILE = /\.(?:[cm]?[jt]sx?)$/;
|
|
1174
1416
|
var federationOptionsByPlugins = /* @__PURE__ */ new WeakMap();
|
|
1175
1417
|
function manifestFile(options) {
|
|
1176
|
-
return options.manifestPath ??
|
|
1418
|
+
return options.manifestPath ?? resolve3(options.root ?? process.cwd(), "tappify.extension.json");
|
|
1177
1419
|
}
|
|
1178
1420
|
function loadManifest(options) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1421
|
+
let raw;
|
|
1422
|
+
try {
|
|
1423
|
+
raw = options.manifest ?? JSON.parse(readFileSync2(manifestFile(options), "utf8"));
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
return {
|
|
1426
|
+
ok: false,
|
|
1427
|
+
issues: [
|
|
1428
|
+
{
|
|
1429
|
+
path: "$",
|
|
1430
|
+
message: error instanceof Error ? `The manifest is not valid JSON: ${error.message}` : "The manifest is not valid JSON."
|
|
1431
|
+
}
|
|
1432
|
+
]
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
return validateManifest(raw);
|
|
1436
|
+
}
|
|
1437
|
+
function manifestError(result) {
|
|
1438
|
+
if (result.ok) throw new Error("A valid manifest has no validation error.");
|
|
1439
|
+
const lines = result.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n");
|
|
1440
|
+
return new TapError(
|
|
1441
|
+
"TAP_MANIFEST_INVALID",
|
|
1442
|
+
`tappify.extension.json does not validate:
|
|
1186
1443
|
${lines}
|
|
1187
1444
|
Fix the fields above, or run \`tappify extension doctor\` for the same list with suggested fixes.`
|
|
1188
|
-
|
|
1189
|
-
}
|
|
1190
|
-
return result.manifest;
|
|
1445
|
+
);
|
|
1191
1446
|
}
|
|
1192
1447
|
function tappifyExtension(options = {}) {
|
|
1193
1448
|
const root = options.root ?? process.cwd();
|
|
1194
1449
|
const boundary = root.endsWith(sep2) ? root : `${root}${sep2}`;
|
|
1195
|
-
const
|
|
1196
|
-
const
|
|
1450
|
+
const loaded = loadManifest(options);
|
|
1451
|
+
const manifest = loaded.ok ? loaded.manifest : null;
|
|
1452
|
+
const contributions = manifest === null ? [] : uiContributions(manifest);
|
|
1197
1453
|
const port = options.port ?? DEFAULT_PORT;
|
|
1198
1454
|
const entryByKey = /* @__PURE__ */ new Map();
|
|
1199
1455
|
const exposes = {};
|
|
1200
1456
|
for (const contribution of contributions) {
|
|
1201
1457
|
const key = contribution.expose.slice("./".length);
|
|
1202
|
-
entryByKey.set(key,
|
|
1458
|
+
entryByKey.set(key, resolve3(root, contribution.entry));
|
|
1203
1459
|
exposes[contribution.expose] = `${VIRTUAL_PREFIX}${key}`;
|
|
1204
1460
|
}
|
|
1205
1461
|
const singleton = { singleton: true, requiredVersion: false };
|
|
1206
1462
|
const federationOptions = {
|
|
1207
|
-
name: remoteName(manifest
|
|
1463
|
+
name: remoteName(manifest?.id ?? "invalid-extension"),
|
|
1208
1464
|
filename: "remoteEntry.js",
|
|
1209
1465
|
manifest: true,
|
|
1210
1466
|
exposes,
|
|
@@ -1260,6 +1516,16 @@ function tappifyExtension(options = {}) {
|
|
|
1260
1516
|
].join("\n");
|
|
1261
1517
|
}
|
|
1262
1518
|
};
|
|
1519
|
+
const guard = {
|
|
1520
|
+
name: "tappify:manifest",
|
|
1521
|
+
enforce: "pre",
|
|
1522
|
+
config(_config, environment) {
|
|
1523
|
+
if (environment.command !== "build") return null;
|
|
1524
|
+
const current = loadManifest(options);
|
|
1525
|
+
if (!current.ok) throw manifestError(current);
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1263
1529
|
const css = {
|
|
1264
1530
|
name: "tappify:css",
|
|
1265
1531
|
enforce: "pre",
|
|
@@ -1272,43 +1538,32 @@ function tappifyExtension(options = {}) {
|
|
|
1272
1538
|
return next === null ? null : { code: next, map: null };
|
|
1273
1539
|
}
|
|
1274
1540
|
};
|
|
1275
|
-
const dev = {
|
|
1276
|
-
name: "tappify:dev",
|
|
1277
|
-
apply: "serve",
|
|
1278
|
-
config() {
|
|
1279
|
-
return {
|
|
1280
|
-
server: {
|
|
1281
|
-
port,
|
|
1282
|
-
strictPort: true,
|
|
1283
|
-
cors: { origin: true },
|
|
1284
|
-
origin: `http://localhost:${String(port)}`
|
|
1285
|
-
}
|
|
1286
|
-
};
|
|
1287
|
-
},
|
|
1288
|
-
configureServer(server) {
|
|
1289
|
-
server.watcher.add(manifestFile(options));
|
|
1290
|
-
},
|
|
1291
|
-
/** Vite runs hotUpdate once per dev environment, and the manifest is one file. */
|
|
1292
|
-
async hotUpdate(context) {
|
|
1293
|
-
if (this.environment.name !== "client") return;
|
|
1294
|
-
if (context.file !== manifestFile(options)) return;
|
|
1295
|
-
if (options.onManifestChange === void 0) return;
|
|
1296
|
-
await options.onManifestChange(loadManifest(options));
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
1541
|
const plugins = [
|
|
1542
|
+
guard,
|
|
1300
1543
|
expose,
|
|
1301
1544
|
css,
|
|
1302
1545
|
...federation(federationOptions),
|
|
1303
|
-
|
|
1546
|
+
...createPreviewPlugins({
|
|
1547
|
+
manifestFile: manifestFile(options),
|
|
1548
|
+
loadManifest: () => loadManifest(options),
|
|
1549
|
+
port,
|
|
1550
|
+
remote: process.env[PREVIEW_REMOTE_ENV],
|
|
1551
|
+
onManifestChange: async (result) => {
|
|
1552
|
+
if (result.ok && options.onManifestChange !== void 0) {
|
|
1553
|
+
await options.onManifestChange(result.manifest);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
})
|
|
1304
1557
|
];
|
|
1305
1558
|
federationOptionsByPlugins.set(plugins, federationOptions);
|
|
1306
1559
|
return plugins;
|
|
1307
1560
|
}
|
|
1308
1561
|
export {
|
|
1562
|
+
PREVIEW_REMOTE_ENV,
|
|
1309
1563
|
VIRTUAL_PREFIX,
|
|
1310
1564
|
collectEntryStyles,
|
|
1311
1565
|
inlineCssImports,
|
|
1566
|
+
previewRemote,
|
|
1312
1567
|
tappifyExtension
|
|
1313
1568
|
};
|
|
1314
1569
|
//# sourceMappingURL=vite.mjs.map
|