@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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/manifest/define.ts
|
|
2
|
+
var EXPOSE_FOLDER = {
|
|
3
|
+
page: "pages",
|
|
4
|
+
tab: "tabs",
|
|
5
|
+
widget: "widgets",
|
|
6
|
+
rowAction: "rowActions"
|
|
7
|
+
};
|
|
8
|
+
function defineManifest(manifest) {
|
|
9
|
+
return manifest;
|
|
10
|
+
}
|
|
11
|
+
function exposeName(kind, id) {
|
|
12
|
+
if (kind === "settings") return "./settings";
|
|
13
|
+
return `./${EXPOSE_FOLDER[kind]}/${_nullishCoalesce(id, () => ( ""))}`;
|
|
14
|
+
}
|
|
15
|
+
function remoteName(extensionId) {
|
|
16
|
+
return `ext_${extensionId.replace(/-/g, "_")}`;
|
|
17
|
+
}
|
|
18
|
+
function uiContributions(manifest) {
|
|
19
|
+
const contributes = manifest.contributes;
|
|
20
|
+
const refs = [];
|
|
21
|
+
for (const page of _nullishCoalesce(contributes.pages, () => ( []))) {
|
|
22
|
+
refs.push({
|
|
23
|
+
kind: "page",
|
|
24
|
+
id: page.id,
|
|
25
|
+
entry: page.entry,
|
|
26
|
+
expose: exposeName("page", page.id)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
for (const tab of _nullishCoalesce(contributes.tabs, () => ( []))) {
|
|
30
|
+
refs.push({
|
|
31
|
+
kind: "tab",
|
|
32
|
+
id: tab.id,
|
|
33
|
+
entry: tab.entry,
|
|
34
|
+
expose: exposeName("tab", tab.id)
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
for (const widget of _nullishCoalesce(contributes.widgets, () => ( []))) {
|
|
38
|
+
refs.push({
|
|
39
|
+
kind: "widget",
|
|
40
|
+
id: widget.id,
|
|
41
|
+
entry: widget.entry,
|
|
42
|
+
expose: exposeName("widget", widget.id)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
for (const rowAction of _nullishCoalesce(contributes.rowActions, () => ( []))) {
|
|
46
|
+
refs.push({
|
|
47
|
+
kind: "rowAction",
|
|
48
|
+
id: rowAction.id,
|
|
49
|
+
entry: rowAction.entry,
|
|
50
|
+
expose: exposeName("rowAction", rowAction.id)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (contributes.settings) {
|
|
54
|
+
refs.push({
|
|
55
|
+
kind: "settings",
|
|
56
|
+
id: "settings",
|
|
57
|
+
entry: contributes.settings.entry,
|
|
58
|
+
expose: exposeName("settings")
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return refs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
exports.defineManifest = defineManifest; exports.exposeName = exposeName; exports.remoteName = remoteName; exports.uiContributions = uiContributions;
|
|
70
|
+
//# sourceMappingURL=chunk-NN263PGQ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-NN263PGQ.cjs","../src/manifest/define.ts"],"names":[],"mappings":"AAAA;ACMA,IAAM,cAAA,EAAoE;AAAA,EACxE,IAAA,EAAM,OAAA;AAAA,EACN,GAAA,EAAK,MAAA;AAAA,EACL,MAAA,EAAQ,SAAA;AAAA,EACR,SAAA,EAAW;AACb,CAAA;AAEO,SAAS,cAAA,CAAe,QAAA,EAAgD;AAC7E,EAAA,OAAO,QAAA;AACT;AAOO,SAAS,UAAA,CAAW,IAAA,EAAqB,EAAA,EAAqB;AACnE,EAAA,GAAA,CAAI,KAAA,IAAS,UAAA,EAAY,OAAO,YAAA;AAChC,EAAA,OAAO,CAAA,EAAA,EAAK,aAAA,CAAc,IAAI,CAAC,CAAA,CAAA,mBAAI,EAAA,UAAM,IAAE,CAAA,CAAA;AAC7C;AAEwD;AACV,EAAA;AAC9C;AAIuB;AACQ,EAAA;AACM,EAAA;AAES,EAAA;AAChC,IAAA;AACF,MAAA;AACG,MAAA;AACG,MAAA;AACsB,MAAA;AACnC,IAAA;AACH,EAAA;AAC0C,EAAA;AAC9B,IAAA;AACF,MAAA;AACE,MAAA;AACG,MAAA;AACqB,MAAA;AACjC,IAAA;AACH,EAAA;AAC4C,EAAA;AAChC,IAAA;AACF,MAAA;AACK,MAAA;AACG,MAAA;AACwB,MAAA;AACvC,IAAA;AACH,EAAA;AACoC,EAAA;AACxB,IAAA;AACF,MAAA;AACQ,MAAA;AACG,MAAA;AACe,MAAA;AACjC,IAAA;AACH,EAAA;AAC0B,EAAA;AACd,IAAA;AACF,MAAA;AACF,MAAA;AACwB,MAAA;AACC,MAAA;AAC9B,IAAA;AACH,EAAA;AAEO,EAAA;AACT;ADjB8C;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-NN263PGQ.cjs","sourcesContent":[null,"import type {\n ExposableKind,\n ExtensionManifest,\n UiContributionRef,\n} from './types';\n\nconst EXPOSE_FOLDER: Record<Exclude<ExposableKind, 'settings'>, string> = {\n page: 'pages',\n tab: 'tabs',\n widget: 'widgets',\n rowAction: 'rowActions',\n};\n\nexport function defineManifest(manifest: ExtensionManifest): ExtensionManifest {\n return manifest;\n}\n\nexport function exposeName(kind: 'settings'): string;\nexport function exposeName(\n kind: Exclude<ExposableKind, 'settings'>,\n id: string,\n): string;\nexport function exposeName(kind: ExposableKind, id?: string): string {\n if (kind === 'settings') return './settings';\n return `./${EXPOSE_FOLDER[kind]}/${id ?? ''}`;\n}\n\nexport function remoteName(extensionId: string): string {\n return `ext_${extensionId.replace(/-/g, '_')}`;\n}\n\nexport function uiContributions(\n manifest: ExtensionManifest,\n): UiContributionRef[] {\n const contributes = manifest.contributes;\n const refs: UiContributionRef[] = [];\n\n for (const page of contributes.pages ?? []) {\n refs.push({\n kind: 'page',\n id: page.id,\n entry: page.entry,\n expose: exposeName('page', page.id),\n });\n }\n for (const tab of contributes.tabs ?? []) {\n refs.push({\n kind: 'tab',\n id: tab.id,\n entry: tab.entry,\n expose: exposeName('tab', tab.id),\n });\n }\n for (const widget of contributes.widgets ?? []) {\n refs.push({\n kind: 'widget',\n id: widget.id,\n entry: widget.entry,\n expose: exposeName('widget', widget.id),\n });\n }\n for (const rowAction of contributes.rowActions ?? []) {\n refs.push({\n kind: 'rowAction',\n id: rowAction.id,\n entry: rowAction.entry,\n expose: exposeName('rowAction', rowAction.id),\n });\n }\n if (contributes.settings) {\n refs.push({\n kind: 'settings',\n id: 'settings',\n entry: contributes.settings.entry,\n expose: exposeName('settings'),\n });\n }\n\n return refs;\n}\n"]}
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunk6HETNZJYcjs = require('./chunk-6HETNZJY.cjs');
|
|
4
4
|
|
|
5
5
|
// src/testing/environment.ts
|
|
6
6
|
var HOST_THEME = {
|
|
7
|
-
"--bg-
|
|
8
|
-
"--bg-
|
|
9
|
-
"--bg-
|
|
10
|
-
"--fg-
|
|
11
|
-
"--fg-
|
|
12
|
-
"--
|
|
13
|
-
"--
|
|
14
|
-
"--
|
|
15
|
-
"--
|
|
16
|
-
"--
|
|
17
|
-
"--
|
|
18
|
-
"--tap-space": "8px",
|
|
19
|
-
"--font-sans": "system-ui, -apple-system, sans-serif",
|
|
20
|
-
"--font-mono": "ui-monospace, SFMono-Regular, monospace",
|
|
21
|
-
"--divider": "rgba(18, 18, 18, 0.12)"
|
|
7
|
+
"--bg-paper": "#fdfdfd",
|
|
8
|
+
"--bg-canvas": "#f2f3ee",
|
|
9
|
+
"--bg-light-gray": "#edf1f5",
|
|
10
|
+
"--fg-primary": "#121212",
|
|
11
|
+
"--fg-sub": "rgba(18, 18, 18, 0.7)",
|
|
12
|
+
"--divider": "#d5d7da",
|
|
13
|
+
"--lime": "#b4d773",
|
|
14
|
+
"--deep-green": "#234e20",
|
|
15
|
+
"--danger": "#b42318",
|
|
16
|
+
"--on-accent": "#ffffff",
|
|
17
|
+
"--font-one-ui": "'Inter Variable', 'Inter', system-ui, sans-serif"
|
|
22
18
|
};
|
|
23
19
|
function installHostTheme(root) {
|
|
24
20
|
for (const [name, value] of Object.entries(HOST_THEME)) {
|
|
@@ -35,7 +31,7 @@ function isMock(value) {
|
|
|
35
31
|
}
|
|
36
32
|
function requireMock(value, matcher) {
|
|
37
33
|
if (isMock(value)) return value;
|
|
38
|
-
throw new (0,
|
|
34
|
+
throw new (0, _chunk6HETNZJYcjs.TapError)(
|
|
39
35
|
"TAP_TEST_TARGET_INVALID",
|
|
40
36
|
`${matcher}() takes the mock renderWithTap() returned. Call it as expect(mock).${matcher}(\u2026), not on the component or the tap object.`
|
|
41
37
|
);
|
|
@@ -139,4 +135,4 @@ function registerTapMatchers(target) {
|
|
|
139
135
|
|
|
140
136
|
|
|
141
137
|
exports.installHostTheme = installHostTheme; exports.clearTapPortals = clearTapPortals; exports.tapMatchers = tapMatchers; exports.registerTapMatchers = registerTapMatchers;
|
|
142
|
-
//# sourceMappingURL=chunk-
|
|
138
|
+
//# sourceMappingURL=chunk-O357OJXL.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-O357OJXL.cjs","../src/testing/environment.ts","../src/testing/matchers.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACJA,IAAM,WAAA,EAAqC;AAAA,EACzC,YAAA,EAAc,SAAA;AAAA,EACd,aAAA,EAAe,SAAA;AAAA,EACf,iBAAA,EAAmB,SAAA;AAAA,EACnB,cAAA,EAAgB,SAAA;AAAA,EAChB,UAAA,EAAY,uBAAA;AAAA,EACZ,WAAA,EAAa,SAAA;AAAA,EACb,QAAA,EAAU,SAAA;AAAA,EACV,cAAA,EAAgB,SAAA;AAAA,EAChB,UAAA,EAAY,SAAA;AAAA,EACZ,aAAA,EAAe,SAAA;AAAA,EACf,eAAA,EAAiB;AACnB,CAAA;AA0BO,SAAS,gBAAA,CAAiB,IAAA,EAAyB;AACxD,EAAA,IAAA,CAAA,MAAW,CAAC,IAAA,EAAM,KAAK,EAAA,GAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,EAAG;AACtD,IAAA,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AAAA,EACpC;AACF;AAEO,SAAS,eAAA,CAAgB,KAAA,EAAmB,QAAA,EAAgB;AACjE,EAAA,IAAA,CAAA,MAAW,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,mBAAmB,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA;AAC7E;ADpBA;AACA;AEXA,SAAS,MAAA,CAAO,KAAA,EAAkC;AAChD,EAAA,OACE,OAAO,MAAA,IAAU,SAAA,GACjB,MAAA,IAAU,KAAA,GACV,QAAA,GAAW,MAAA,GACX,YAAA,GAAe,MAAA,GACf,OAAO,KAAA,CAAM,UAAA,IAAc,UAAA;AAE/B;AAEA,SAAS,WAAA,CAAY,KAAA,EAAgB,OAAA,EAA0B;AAC7D,EAAA,GAAA,CAAI,MAAA,CAAO,KAAK,CAAA,EAAG,OAAO,KAAA;AAC1B,EAAA,MAAM,IAAI,+BAAA;AAAA,IACR,yBAAA;AAAA,IACA,CAAA,EAAA;AACF,EAAA;AACF;AAEA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AAIF;AAEA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AAEA,EAAA;AACA,EAAA;AAEA,EAAA;AAME,IAAA;AACF,EAAA;AAEA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AAEA,EAAA;AACA,EAAA;AAGI,IAAA;AAEF,EAAA;AAEJ;AA2Ba;AAAc;AAEzB,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAO,MAAA;AACL,MAAA;AASF,IAAA;AACF,EAAA;AAAA;AAGA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAsB,MAAA;AAItB,IAAA;AACA,IAAA;AAAO,MAAA;AACL,MAAA;AAOF,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAAA;AAMA,EAAA;AAKE,IAAA;AACA,IAAA;AACA,IAAA;AAIA,IAAA;AAAO,MAAA;AACL,MAAA;AAWF,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAAA;AAMA,EAAA;AAKE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAAO,MAAA;AACL,MAAA;AAOF,IAAA;AACF,EAAA;AACF;AAqBO;AACL,EAAA;AACF;AFtGK;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-O357OJXL.cjs","sourcesContent":[null,"const HOST_THEME: Record<string, string> = {\n '--bg-paper': '#fdfdfd',\n '--bg-canvas': '#f2f3ee',\n '--bg-light-gray': '#edf1f5',\n '--fg-primary': '#121212',\n '--fg-sub': 'rgba(18, 18, 18, 0.7)',\n '--divider': '#d5d7da',\n '--lime': '#b4d773',\n '--deep-green': '#234e20',\n '--danger': '#b42318',\n '--on-accent': '#ffffff',\n '--font-one-ui': \"'Inter Variable', 'Inter', system-ui, sans-serif\",\n};\n\n/**\n * Sets the host's eleven One UI CSS variables on an element, so a component renders in\n * a test the way it renders in the host.\n *\n * @remarks\n * Sets the light values as inline custom properties, which inherit into everything\n * below the element. The vitest and jest presets call it on\n * `document.documentElement` for you, so call it yourself only in a test that\n * renders outside `renderWithTap` or wants the variables on one subtree. It sets\n * no dark values; drive the mode through `renderWithTap`'s `theme` option, which\n * is what `useTapTheme` reads.\n *\n * @example\n * ```ts\n * import { installHostTheme } from '@tappify/extension-sdk/testing';\n *\n * function mountRoot(): HTMLElement {\n * const root = document.createElement('div');\n * installHostTheme(root);\n * document.body.append(root);\n * return root;\n * }\n * ```\n */\nexport function installHostTheme(root: HTMLElement): void {\n for (const [name, value] of Object.entries(HOST_THEME)) {\n root.style.setProperty(name, value);\n }\n}\n\nexport function clearTapPortals(root: ParentNode = document): void {\n for (const node of root.querySelectorAll('[data-tap-portal]')) node.remove();\n}\n","import { TapError } from '../client/errors';\nimport type { TapMock } from './mock';\n\n/** What each matcher returns, in the shape vitest and jest both read. */\nexport interface MatcherResult {\n pass: boolean;\n /** Built only when the runner reports, and worded for both `expect` and `not`. */\n message(): string;\n}\n\n/** The part of a runner's `expect` that `registerTapMatchers` needs. */\nexport interface MatcherTarget {\n /** Both runners take a map of matcher functions keyed by matcher name. */\n extend(matchers: Record<string, unknown>): void;\n}\n\nfunction isMock(value: unknown): value is TapMock {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'calls' in value &&\n 'documents' in value &&\n typeof value.documents === 'function'\n );\n}\n\nfunction requireMock(value: unknown, matcher: string): TapMock {\n if (isMock(value)) return value;\n throw new TapError(\n 'TAP_TEST_TARGET_INVALID',\n `${matcher}() takes the mock renderWithTap() returned. Call it as expect(mock).${matcher}(…), not on the component or the tap object.`,\n );\n}\n\nfunction tagOf(value: unknown): string {\n return Object.prototype.toString.call(value);\n}\n\nfunction sameList(left: unknown[], right: unknown[]): boolean {\n return (\n left.length === right.length &&\n left.every((item, index) => same(item, right[index]))\n );\n}\n\nfunction bytesOf(view: ArrayBufferView): number[] {\n return [...new Uint8Array(view.buffer, view.byteOffset, view.byteLength)];\n}\n\nfunction same(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) return true;\n\n const tag = tagOf(left);\n if (tag !== tagOf(right)) return false;\n\n if (\n typeof left !== 'object' ||\n typeof right !== 'object' ||\n left === null ||\n right === null\n ) {\n return false;\n }\n\n if (left instanceof Date && right instanceof Date) {\n return left.valueOf() === right.valueOf();\n }\n if (left instanceof RegExp && right instanceof RegExp) {\n return left.source === right.source && left.flags === right.flags;\n }\n if (left instanceof Map && right instanceof Map) {\n return sameList([...left.entries()], [...right.entries()]);\n }\n if (left instanceof Set && right instanceof Set) {\n return sameList([...left.values()], [...right.values()]);\n }\n if (ArrayBuffer.isView(left) && ArrayBuffer.isView(right)) {\n return sameList(bytesOf(left), bytesOf(right));\n }\n if (Array.isArray(left) && Array.isArray(right)) {\n return sameList(left, right);\n }\n if (tag !== '[object Object]') return false;\n\n const keys = Object.keys(left);\n return (\n keys.length === Object.keys(right).length &&\n keys.every(\n key =>\n key in right && same(Reflect.get(left, key), Reflect.get(right, key)),\n )\n );\n}\n\n/**\n * The four matchers that assert on what a component asked the host to do.\n *\n * @remarks\n * Each takes the mock `renderWithTap` returns, so the assertion is\n * `expect(mock).toHaveToasted(…)` rather than `expect(component)`; anything else\n * throws a `TapError` carrying `TAP_TEST_TARGET_INVALID`. A failure names every\n * call that was recorded, so a wrong path or message reads without a debugger. The\n * vitest and jest presets register these, and both declare the four on the runner's\n * own `Matchers` interface, so `expect(mock).toHaveToasted` typechecks once the\n * preset is in the setup files.\n *\n * @example\n * ```ts\n * import '@tappify/extension-sdk/testing/vitest';\n * import { createTapMock } from '@tappify/extension-sdk/testing';\n * import { expect, it } from 'vitest';\n *\n * it('toasts when a release ships', () => {\n * const mock = createTapMock();\n * mock.tap.ui.toast('A release shipped', 'neutral');\n * expect(mock).toHaveToasted('A release shipped');\n * });\n * ```\n */\nexport const tapMatchers = {\n /** Passes when `tap.nav.push` was called with exactly that path. */\n toHaveNavigatedTo(received: unknown, path: string): MatcherResult {\n const mock = requireMock(received, 'toHaveNavigatedTo');\n const pass = mock.calls.navigations.includes(path);\n return {\n pass,\n message: () =>\n pass\n ? `Expected no navigation to ${path}, but tap.nav.push was called with it.`\n : `Expected a navigation to ${path}. tap.nav.push was called with: ${\n mock.calls.navigations.length === 0\n ? 'nothing'\n : mock.calls.navigations.join(', ')\n }.`,\n };\n },\n\n /** Passes when a toast matched the string exactly, or the pattern anywhere. */\n toHaveToasted(received: unknown, expected: string | RegExp): MatcherResult {\n const mock = requireMock(received, 'toHaveToasted');\n const messages = mock.calls.toasts.map(toast => toast.message);\n const pass = messages.some(message =>\n typeof expected === 'string'\n ? message === expected\n : expected.test(message),\n );\n return {\n pass,\n message: () =>\n pass\n ? `Expected no toast matching ${String(expected)}, but one was shown.`\n : `Expected a toast matching ${String(expected)}. Toasts shown: ${\n messages.length === 0 ? 'none' : messages.join(' | ')\n }.`,\n };\n },\n\n /**\n * Passes when `tap.actions.run` was called with that action, and with input\n * deep-equal to `input` when one is given.\n */\n toHaveRunAction(\n received: unknown,\n actionId: string,\n input?: unknown,\n ): MatcherResult {\n const mock = requireMock(received, 'toHaveRunAction');\n const runs = mock.calls.actions.filter(run => run.actionId === actionId);\n const pass =\n input === undefined\n ? runs.length > 0\n : runs.some(run => same(run.input, input));\n return {\n pass,\n message: () =>\n pass\n ? `Expected tap.actions.run(\"${actionId}\") not to be called.`\n : `Expected tap.actions.run(\"${actionId}\"${\n input === undefined ? '' : `, ${JSON.stringify(input)}`\n }). Runs recorded: ${\n mock.calls.actions.length === 0\n ? 'none'\n : JSON.stringify(mock.calls.actions)\n }.`,\n };\n },\n\n /**\n * Passes when the mock's storage holds a document deep-equal to that one in\n * that collection.\n */\n toHaveStored(\n received: unknown,\n collection: string,\n document: unknown,\n ): MatcherResult {\n const mock = requireMock(received, 'toHaveStored');\n const stored = mock.documents(collection);\n const pass = stored.some(candidate => same(candidate, document));\n return {\n pass,\n message: () =>\n pass\n ? `Expected \"${collection}\" not to hold ${JSON.stringify(document)}.`\n : `Expected \"${collection}\" to hold ${JSON.stringify(document)}. It holds: ${\n stored.length === 0 ? 'nothing' : JSON.stringify(stored)\n }.`,\n };\n },\n};\n\n/**\n * Registers the four matchers on a runner's `expect`.\n *\n * @remarks\n * The vitest and jest presets call this, so a suite that loads\n * `@tappify/extension-sdk/testing/vitest` or `.../testing/jest` as a setup file\n * needs nothing else. Call it yourself only in a suite that does not use a preset,\n * and once — registering twice replaces the same four names. It adds no types of\n * its own, so a suite without a preset declares the four on the runner's `Matchers`\n * interface itself.\n *\n * @example\n * ```ts\n * import { registerTapMatchers } from '@tappify/extension-sdk/testing';\n * import { expect } from 'vitest';\n *\n * registerTapMatchers(expect);\n * ```\n */\nexport function registerTapMatchers(target: MatcherTarget): void {\n target.extend(tapMatchers);\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var _chunkGAUZYBXEcjs = require('./chunk-GAUZYBXE.cjs');
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
var _chunkPRCZMOLDcjs = require('./chunk-PRCZMOLD.cjs');
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
var _chunk6HETNZJYcjs = require('./chunk-6HETNZJY.cjs');
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
var _chunkQ7SFCCGTcjs = require('./chunk-Q7SFCCGT.cjs');
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
_chunkQ7SFCCGTcjs.__export.call(void 0, src_exports, {
|
|
34
|
+
TAP_ERROR_CODES: () => _chunk6HETNZJYcjs.TAP_ERROR_CODES,
|
|
35
|
+
TapError: () => _chunk6HETNZJYcjs.TapError,
|
|
36
|
+
TapServerError: () => _chunk6HETNZJYcjs.TapServerError,
|
|
37
|
+
dataQueryKey: () => _chunkGAUZYBXEcjs.dataQueryKey,
|
|
38
|
+
installPrefix: () => _chunkGAUZYBXEcjs.installPrefix,
|
|
39
|
+
procedurePrefix: () => _chunkGAUZYBXEcjs.procedurePrefix,
|
|
40
|
+
procedureQueryKey: () => _chunkGAUZYBXEcjs.procedureQueryKey,
|
|
41
|
+
storageQueryKey: () => _chunkGAUZYBXEcjs.storageQueryKey,
|
|
42
|
+
useTap: () => _chunkPRCZMOLDcjs.useTap,
|
|
43
|
+
useTapAuth: () => _chunkGAUZYBXEcjs.useTapAuth,
|
|
44
|
+
useTapContext: () => _chunkGAUZYBXEcjs.useTapContext,
|
|
45
|
+
useTapFilters: () => _chunkGAUZYBXEcjs.useTapFilters,
|
|
46
|
+
useTapParams: () => _chunkGAUZYBXEcjs.useTapParams,
|
|
47
|
+
useTapProject: () => _chunkGAUZYBXEcjs.useTapProject,
|
|
48
|
+
useTapQuery: () => _chunkGAUZYBXEcjs.useTapQuery,
|
|
49
|
+
useTapServer: () => _chunkGAUZYBXEcjs.useTapServer,
|
|
50
|
+
useTapSize: () => _chunkGAUZYBXEcjs.useTapSize,
|
|
51
|
+
useTapState: () => _chunkGAUZYBXEcjs.useTapState,
|
|
52
|
+
useTapStorage: () => _chunkGAUZYBXEcjs.useTapStorage,
|
|
53
|
+
useTapTheme: () => _chunkGAUZYBXEcjs.useTapTheme
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
exports.src_exports = src_exports;
|
|
59
|
+
//# sourceMappingURL=chunk-ONJMPO3P.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-ONJMPO3P.cjs","../src/index.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACA;AC9BA,IAAA,YAAA,EAAA,CAAA,CAAA;AAAA,wCAAA,WAAA,EAAA;AAAA,EAAA,eAAA,EAAA,CAAA,EAAA,GAAA,iCAAA;AAAA,EAAA,QAAA,EAAA,CAAA,EAAA,GAAA,0BAAA;AAAA,EAAA,cAAA,EAAA,CAAA,EAAA,GAAA,gCAAA;AAAA,EAAA,YAAA,EAAA,CAAA,EAAA,GAAA,8BAAA;AAAA,EAAA,aAAA,EAAA,CAAA,EAAA,GAAA,+BAAA;AAAA,EAAA,eAAA,EAAA,CAAA,EAAA,GAAA,iCAAA;AAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,GAAA,mCAAA;AAAA,EAAA,eAAA,EAAA,CAAA,EAAA,GAAA,iCAAA;AAAA,EAAA,MAAA,EAAA,CAAA,EAAA,GAAA,wBAAA;AAAA,EAAA,UAAA,EAAA,CAAA,EAAA,GAAA,4BAAA;AAAA,EAAA,aAAA,EAAA,CAAA,EAAA,GAAA,+BAAA;AAAA,EAAA,aAAA,EAAA,CAAA,EAAA,GAAA,+BAAA;AAAA,EAAA,YAAA,EAAA,CAAA,EAAA,GAAA,8BAAA;AAAA,EAAA,aAAA,EAAA,CAAA,EAAA,GAAA,+BAAA;AAAA,EAAA,WAAA,EAAA,CAAA,EAAA,GAAA,6BAAA;AAAA,EAAA,YAAA,EAAA,CAAA,EAAA,GAAA,8BAAA;AAAA,EAAA,UAAA,EAAA,CAAA,EAAA,GAAA,4BAAA;AAAA,EAAA,WAAA,EAAA,CAAA,EAAA,GAAA,6BAAA;AAAA,EAAA,aAAA,EAAA,CAAA,EAAA,GAAA,+BAAA;AAAA,EAAA,WAAA,EAAA,CAAA,EAAA,GAAA;AAAA,CAAA,CAAA;ADsDA;AACA;AACE;AACF,kCAAC","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-ONJMPO3P.cjs","sourcesContent":[null,"/**\n * @module index\n * @mergeModuleWith <project>\n */\nexport { useTap } from './client/context';\nexport { TAP_ERROR_CODES, TapError, TapServerError } from './client/errors';\nexport type { TapErrorCode } from './client/errors';\nexport {\n useTapAuth,\n useTapContext,\n useTapFilters,\n useTapParams,\n useTapProject,\n useTapSize,\n useTapState,\n useTapTheme,\n} from './client/hooks';\nexport {\n dataQueryKey,\n installPrefix,\n procedurePrefix,\n procedureQueryKey,\n storageQueryKey,\n useTapQuery,\n useTapServer,\n useTapStorage,\n} from './client/query';\nexport type {\n TapQueryOptions,\n TapQueryResult,\n TapStorageResult,\n} from './client/query';\nexport type * from './client/types';\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunk6HETNZJYcjs = require('./chunk-6HETNZJY.cjs');
|
|
4
4
|
|
|
5
5
|
// src/client/context.ts
|
|
6
6
|
var _react = require('react');
|
|
@@ -18,7 +18,7 @@ var TapContext = resolveContext();
|
|
|
18
18
|
function useTap() {
|
|
19
19
|
const tap = _react.useContext.call(void 0, TapContext);
|
|
20
20
|
if (tap === null) {
|
|
21
|
-
throw new (0,
|
|
21
|
+
throw new (0, _chunk6HETNZJYcjs.TapError)(
|
|
22
22
|
"TAP_OUTSIDE_HOST",
|
|
23
23
|
"useTap() ran outside a Tappify mount. Render this component from an entry declared in tappify.extension.json, or wrap it in renderWithTap() from @tappify/extension-sdk/testing."
|
|
24
24
|
);
|
|
@@ -30,4 +30,4 @@ function useTap() {
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
exports.TapContext = TapContext; exports.useTap = useTap;
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
33
|
+
//# sourceMappingURL=chunk-PRCZMOLD.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-PRCZMOLD.cjs","../src/client/context.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACJA,8BAAwD;AAIxD,IAAM,aAAA,EAAe,qCAAA;AAMrB,IAAM,SAAA,EAAgD,UAAA;AAEtD,SAAS,cAAA,CAAA,EAAsC;AAC7C,EAAA,MAAM,SAAA,EAAW,QAAA,CAAS,YAAY,CAAA;AACtC,EAAA,GAAA,CAAI,QAAA,EAAU,OAAO,QAAA;AAErB,EAAA,MAAM,QAAA,EAAU,kCAAA,IAA8B,CAAA;AAC9C,EAAA,OAAA,CAAQ,YAAA,EAAc,YAAA;AACtB,EAAA,QAAA,CAAS,YAAY,EAAA,EAAI,OAAA;AACzB,EAAA,OAAO,OAAA;AACT;AAEO,IAAM,WAAA,EAAkC,cAAA,CAAe,CAAA;AA0BvD,SAAS,MAAA,CAAA,EAAc;AAC5B,EAAA,MAAM,IAAA,EAAM,+BAAA,UAAqB,CAAA;AACjC,EAAA,GAAA,CAAI,IAAA,IAAQ,IAAA,EAAM;AAChB,IAAA,MAAM,IAAI,+BAAA;AAAA,MACR,kBAAA;AAAA,MACA;AAAA,IACF,CAAA;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AD9BA;AACA;AACE;AACA;AACF,yDAAC","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-PRCZMOLD.cjs","sourcesContent":[null,"import { createContext, useContext, type Context } from 'react';\nimport { TapError } from './errors';\nimport type { Tap } from './types';\n\nconst REGISTRY_KEY = '__tappifyExtensionSdkTapContextV2__';\n\ninterface ContextRegistry {\n [REGISTRY_KEY]?: Context<Tap | null>;\n}\n\nconst registry: typeof globalThis & ContextRegistry = globalThis;\n\nfunction resolveContext(): Context<Tap | null> {\n const existing = registry[REGISTRY_KEY];\n if (existing) return existing;\n\n const created = createContext<Tap | null>(null);\n created.displayName = 'TapContext';\n registry[REGISTRY_KEY] = created;\n return created;\n}\n\nexport const TapContext: Context<Tap | null> = resolveContext();\n\n/**\n * Returns the whole bridge the host mounted this component with.\n *\n * @remarks\n * Throws `TapError` with code `TAP_OUTSIDE_HOST` when no Tappify mount is above\n * the component. The object it returns does not re-render the component when the\n * host changes a member; read through `useTapFilters`, `useTapTheme` and the\n * other slice hooks where that matters.\n *\n * @example\n * ```tsx\n * import { useTap } from '@tappify/extension-sdk';\n * import { Button } from '@tappify/extension-sdk/ui';\n *\n * function CopyId() {\n * const tap = useTap();\n * return (\n * <Button onClick={() => void tap.ui.copy(tap.project.id)}>\n * Copy project id\n * </Button>\n * );\n * }\n * ```\n */\nexport function useTap(): Tap {\n const tap = useContext(TapContext);\n if (tap === null) {\n throw new TapError(\n 'TAP_OUTSIDE_HOST',\n 'useTap() ran outside a Tappify mount. Render this component from an entry declared in tappify.extension.json, or wrap it in renderWithTap() from @tappify/extension-sdk/testing.',\n );\n }\n return tap;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
exports.__export = __export;
|
|
10
|
+
//# sourceMappingURL=chunk-Q7SFCCGT.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-Q7SFCCGT.cjs"],"names":[],"mappings":"AAAA,6EAAI,UAAU,EAAE,MAAM,CAAC,cAAc;AACrC,IAAI,SAAS,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG;AAChC,EAAE,IAAI,CAAC,IAAI,KAAK,GAAG,GAAG;AACtB,IAAI,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;AACjE,CAAC;AACD;AACA;AACE;AACF,4BAAC","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-Q7SFCCGT.cjs"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TapError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QXD7WVKK.mjs";
|
|
4
4
|
|
|
5
5
|
// src/client/context.ts
|
|
6
6
|
import { createContext, useContext } from "react";
|
|
@@ -30,4 +30,4 @@ export {
|
|
|
30
30
|
TapContext,
|
|
31
31
|
useTap
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
33
|
+
//# sourceMappingURL=chunk-QA5AL3VZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/context.ts"],"sourcesContent":["import { createContext, useContext, type Context } from 'react';\nimport { TapError } from './errors';\nimport type { Tap } from './types';\n\nconst REGISTRY_KEY = '__tappifyExtensionSdkTapContextV2__';\n\ninterface ContextRegistry {\n [REGISTRY_KEY]?: Context<Tap | null>;\n}\n\nconst registry: typeof globalThis & ContextRegistry = globalThis;\n\nfunction resolveContext(): Context<Tap | null> {\n const existing = registry[REGISTRY_KEY];\n if (existing) return existing;\n\n const created = createContext<Tap | null>(null);\n created.displayName = 'TapContext';\n registry[REGISTRY_KEY] = created;\n return created;\n}\n\nexport const TapContext: Context<Tap | null> = resolveContext();\n\n/**\n * Returns the whole bridge the host mounted this component with.\n *\n * @remarks\n * Throws `TapError` with code `TAP_OUTSIDE_HOST` when no Tappify mount is above\n * the component. The object it returns does not re-render the component when the\n * host changes a member; read through `useTapFilters`, `useTapTheme` and the\n * other slice hooks where that matters.\n *\n * @example\n * ```tsx\n * import {
|
|
1
|
+
{"version":3,"sources":["../src/client/context.ts"],"sourcesContent":["import { createContext, useContext, type Context } from 'react';\nimport { TapError } from './errors';\nimport type { Tap } from './types';\n\nconst REGISTRY_KEY = '__tappifyExtensionSdkTapContextV2__';\n\ninterface ContextRegistry {\n [REGISTRY_KEY]?: Context<Tap | null>;\n}\n\nconst registry: typeof globalThis & ContextRegistry = globalThis;\n\nfunction resolveContext(): Context<Tap | null> {\n const existing = registry[REGISTRY_KEY];\n if (existing) return existing;\n\n const created = createContext<Tap | null>(null);\n created.displayName = 'TapContext';\n registry[REGISTRY_KEY] = created;\n return created;\n}\n\nexport const TapContext: Context<Tap | null> = resolveContext();\n\n/**\n * Returns the whole bridge the host mounted this component with.\n *\n * @remarks\n * Throws `TapError` with code `TAP_OUTSIDE_HOST` when no Tappify mount is above\n * the component. The object it returns does not re-render the component when the\n * host changes a member; read through `useTapFilters`, `useTapTheme` and the\n * other slice hooks where that matters.\n *\n * @example\n * ```tsx\n * import { useTap } from '@tappify/extension-sdk';\n * import { Button } from '@tappify/extension-sdk/ui';\n *\n * function CopyId() {\n * const tap = useTap();\n * return (\n * <Button onClick={() => void tap.ui.copy(tap.project.id)}>\n * Copy project id\n * </Button>\n * );\n * }\n * ```\n */\nexport function useTap(): Tap {\n const tap = useContext(TapContext);\n if (tap === null) {\n throw new TapError(\n 'TAP_OUTSIDE_HOST',\n 'useTap() ran outside a Tappify mount. Render this component from an entry declared in tappify.extension.json, or wrap it in renderWithTap() from @tappify/extension-sdk/testing.',\n );\n }\n return tap;\n}\n"],"mappings":";;;;;AAAA,SAAS,eAAe,kBAAgC;AAIxD,IAAM,eAAe;AAMrB,IAAM,WAAgD;AAEtD,SAAS,iBAAsC;AAC7C,QAAM,WAAW,SAAS,YAAY;AACtC,MAAI,SAAU,QAAO;AAErB,QAAM,UAAU,cAA0B,IAAI;AAC9C,UAAQ,cAAc;AACtB,WAAS,YAAY,IAAI;AACzB,SAAO;AACT;AAEO,IAAM,aAAkC,eAAe;AA0BvD,SAAS,SAAc;AAC5B,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,QAAQ,MAAM;AAChB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SERVER_ERROR_CODES,
|
|
3
|
+
readRecord,
|
|
4
|
+
readText,
|
|
5
|
+
readUnknown
|
|
6
|
+
} from "./chunk-KZ5NGFUP.mjs";
|
|
7
|
+
import {
|
|
8
|
+
TapServerError
|
|
9
|
+
} from "./chunk-QXD7WVKK.mjs";
|
|
10
|
+
|
|
11
|
+
// src/server/events.ts
|
|
12
|
+
var DEFAULT_BASE_URL = "https://api.tappify.ai";
|
|
13
|
+
function toHex(buffer) {
|
|
14
|
+
return Array.from(new Uint8Array(buffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
15
|
+
}
|
|
16
|
+
async function signWebhook(secret, body) {
|
|
17
|
+
const encoder = new TextEncoder();
|
|
18
|
+
const key = await crypto.subtle.importKey(
|
|
19
|
+
"raw",
|
|
20
|
+
encoder.encode(secret),
|
|
21
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
22
|
+
false,
|
|
23
|
+
["sign"]
|
|
24
|
+
);
|
|
25
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(body));
|
|
26
|
+
return toHex(signature);
|
|
27
|
+
}
|
|
28
|
+
async function rejectionCode(response) {
|
|
29
|
+
try {
|
|
30
|
+
const payload = await response.json();
|
|
31
|
+
return readText(readRecord(payload, "error"), "code");
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function sendEvent(name, payload, options) {
|
|
37
|
+
const envelope = {
|
|
38
|
+
event: name,
|
|
39
|
+
source: options.extensionId,
|
|
40
|
+
occurredAt: options.occurredAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
41
|
+
dedupeKey: options.dedupeKey ?? crypto.randomUUID(),
|
|
42
|
+
payload: { ...payload }
|
|
43
|
+
};
|
|
44
|
+
if (options.build !== void 0) envelope.build = options.build;
|
|
45
|
+
const body = JSON.stringify(envelope);
|
|
46
|
+
const signature = await signWebhook(options.secret, body);
|
|
47
|
+
const url = options.endpoint ?? `${options.baseUrl ?? DEFAULT_BASE_URL}/api/v1/extensions/hooks/${options.extensionId}/${options.installId}`;
|
|
48
|
+
const send = options.fetch ?? fetch;
|
|
49
|
+
const response = await send(url, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: {
|
|
52
|
+
"content-type": "application/json",
|
|
53
|
+
"x-tappify-signature": signature
|
|
54
|
+
},
|
|
55
|
+
body
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const rejection = await rejectionCode(response);
|
|
59
|
+
throw new TapServerError(
|
|
60
|
+
SERVER_ERROR_CODES.WEBHOOK_REJECTED,
|
|
61
|
+
`Tappify answered ${String(response.status)}${rejection === null ? "" : ` (${rejection})`} for ${name}. Check the inbound signing secret on the extension's Server page, and that the event is declared under contributes.webhooks.`,
|
|
62
|
+
response.status
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/server/work-events.ts
|
|
68
|
+
function nonempty(value) {
|
|
69
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
70
|
+
}
|
|
71
|
+
function validEvent(event) {
|
|
72
|
+
const type = readText(event, "type");
|
|
73
|
+
if (!["comment.created", "status.changed", "item.deleted"].includes(type ?? ""))
|
|
74
|
+
return false;
|
|
75
|
+
if (!["externalItemId", "providerEventId", "occurredAt", "dedupeKey"].every(
|
|
76
|
+
(key) => nonempty(readUnknown(event, key))
|
|
77
|
+
))
|
|
78
|
+
return false;
|
|
79
|
+
const reference = readUnknown(event, "hydrateRef");
|
|
80
|
+
const comment = readUnknown(event, "comment");
|
|
81
|
+
const status = readUnknown(event, "status");
|
|
82
|
+
if (reference !== void 0)
|
|
83
|
+
return nonempty(reference) && comment === void 0 && status === void 0;
|
|
84
|
+
if (type === "item.deleted")
|
|
85
|
+
return comment === void 0 && status === void 0;
|
|
86
|
+
if (type === "status.changed") {
|
|
87
|
+
const normalized2 = readRecord(event, "status");
|
|
88
|
+
return comment === void 0 && nonempty(normalized2.id) && nonempty(normalized2.label) && typeof normalized2.stage === "string" && ["open", "in_progress", "done"].includes(normalized2.stage);
|
|
89
|
+
}
|
|
90
|
+
const normalized = readRecord(event, "comment");
|
|
91
|
+
const author = readRecord(normalized, "author");
|
|
92
|
+
return status === void 0 && nonempty(normalized.externalCommentId) && typeof normalized.body === "string" && nonempty(normalized.createdAt) && nonempty(author.id) && nonempty(author.displayName);
|
|
93
|
+
}
|
|
94
|
+
async function sendWorkEvent(event, options) {
|
|
95
|
+
if (!validEvent(event))
|
|
96
|
+
throw new TypeError(
|
|
97
|
+
"Invalid work event: provide complete normalized content or a nonempty hydrateRef, with routing and identity fields."
|
|
98
|
+
);
|
|
99
|
+
if (!nonempty(options.callbackUrl))
|
|
100
|
+
throw new TypeError(
|
|
101
|
+
"A work event requires the callbackUrl provisioned through configure."
|
|
102
|
+
);
|
|
103
|
+
const body = JSON.stringify(event);
|
|
104
|
+
const signature = await signWebhook(options.secret, body);
|
|
105
|
+
const response = await (options.fetch ?? fetch)(options.callbackUrl, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
"content-type": "application/json",
|
|
109
|
+
"x-tappify-signature": signature
|
|
110
|
+
},
|
|
111
|
+
body
|
|
112
|
+
});
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
let rejection = null;
|
|
115
|
+
try {
|
|
116
|
+
rejection = readText(readRecord(await response.json(), "error"), "code");
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
throw new TapServerError(
|
|
120
|
+
SERVER_ERROR_CODES.WEBHOOK_REJECTED,
|
|
121
|
+
`Tappify answered ${String(response.status)}${rejection === null ? "" : ` (${rejection})`} for work event ${event.type}. Check the callback URL and per-install work-event signing secret provisioned through configure.`,
|
|
122
|
+
response.status
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
signWebhook,
|
|
129
|
+
sendEvent,
|
|
130
|
+
sendWorkEvent
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=chunk-QJMZRV7A.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/events.ts","../src/server/work-events.ts"],"sourcesContent":["import { TapServerError } from '../client/errors';\nimport type { WebhookName, WebhookPayload } from '../client/types';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { readRecord, readText } from './wire';\n\n/** The body `sendEvent` posts to Tappify, and the body the signature covers. */\nexport interface WebhookEnvelope {\n /** The declared webhook name. */\n event: string;\n /** The extension id the event came from. */\n source: string;\n /** When the event happened, as an ISO timestamp. */\n occurredAt: string;\n /** The build the event belongs to, when it belongs to one. */\n build?: string;\n /** The key Tappify deduplicates on, so a retry is not counted twice. */\n dedupeKey: string;\n payload: Record<string, unknown>;\n}\n\n/** The third argument of `sendEvent`. */\nexport interface SendEventOptions {\n /** Which install the event belongs to. */\n installId: string;\n extensionId: string;\n /** The inbound signing secret from the extension's Server page. */\n secret: string;\n /** A full url to post to, which replaces `baseUrl` and the built path. */\n endpoint?: string;\n /** The Tappify origin to build the path under. Defaults to production. */\n baseUrl?: string;\n /** Defaults to a fresh UUID, so give your own to make a retry idempotent. */\n dedupeKey?: string;\n build?: string;\n /** Defaults to now, in ISO form. */\n occurredAt?: string;\n /** A `fetch` of your own, for a test or a proxy. Defaults to the global one. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.tappify.ai';\n\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Returns the hex HMAC-SHA-256 of a raw body under a shared secret.\n *\n * @remarks\n * This is the value `sendEvent` sends as `X-Tappify-Signature`, computed over the\n * exact bytes of the body it posts. Call it directly only when you build the\n * request yourself, and sign the serialised string you send rather than\n * re-serialising the object, because a different key order is a different\n * signature. Uses Web Crypto, so it runs on Node, Cloudflare Workers and Vercel\n * alike.\n *\n * @example\n * ```ts\n * import { signWebhook } from '@tappify/extension-sdk/server';\n *\n * async function signed(body: string): Promise<Record<string, string>> {\n * return { 'x-tappify-signature': await signWebhook('whsec_test', body) };\n * }\n * ```\n */\nexport async function signWebhook(\n secret: string,\n body: string,\n): Promise<string> {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(body));\n return toHex(signature);\n}\n\nasync function rejectionCode(response: Response): Promise<string | null> {\n try {\n const payload: unknown = await response.json();\n return readText(readRecord(payload, 'error'), 'code');\n } catch {\n return null;\n }\n}\n\n/**\n * Posts one of your declared webhook events to Tappify, signed with the install's\n * inbound secret.\n *\n * @remarks\n * The name and the payload are narrowed by the `TapWebhookMap` augmentation\n * `tappify extension types` writes. It builds the envelope, signs the serialised\n * body and posts it to the install's hook path under `baseUrl`, or to `endpoint`\n * when you give one. A response Tappify did not accept rejects with a\n * `TapServerError` whose `code` is always `TAP_WEBHOOK_REJECTED`, carrying the HTTP\n * status, and with Tappify's own code in the message text rather than in `code`;\n * the two usual causes are the wrong signing\n * secret and an event the manifest does not declare. Pass your own `dedupeKey` to\n * make a retry idempotent, because the default is a fresh UUID.\n *\n * @example\n * ```ts\n * import { sendEvent } from '@tappify/extension-sdk/server';\n *\n * async function reportAnomaly(installId: string, why: string): Promise<void> {\n * await sendEvent('anomaly.detected', { why }, {\n * installId,\n * extensionId: 'starter',\n * secret: process.env.TAPPIFY_INBOUND_SECRET ?? '',\n * dedupeKey: `anomaly-${installId}-${why}`,\n * });\n * }\n * ```\n */\nexport async function sendEvent<E extends WebhookName>(\n name: E,\n payload: WebhookPayload<E>,\n options: SendEventOptions,\n): Promise<void> {\n const envelope: WebhookEnvelope = {\n event: name,\n source: options.extensionId,\n occurredAt: options.occurredAt ?? new Date().toISOString(),\n dedupeKey: options.dedupeKey ?? crypto.randomUUID(),\n payload: { ...payload },\n };\n\n if (options.build !== undefined) envelope.build = options.build;\n\n const body = JSON.stringify(envelope);\n const signature = await signWebhook(options.secret, body);\n const url =\n options.endpoint ??\n `${options.baseUrl ?? DEFAULT_BASE_URL}/api/v1/extensions/hooks/${options.extensionId}/${options.installId}`;\n\n const send = options.fetch ?? fetch;\n const response = await send(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n const rejection = await rejectionCode(response);\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for ${name}. Check the inbound signing secret on the extension's Server page, and that the event is declared under contributes.webhooks.`,\n response.status,\n );\n }\n}\n","import { TapServerError } from '../client/errors';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { signWebhook } from './events';\nimport { readRecord, readText, readUnknown } from './wire';\nimport type { WorkHydratedEvent, WorkHydratedEventBase } from './work';\n\n/** An opaque provider signal to hydrate using current install credentials. */\nexport interface WorkHydrationReferenceEvent extends WorkHydratedEventBase {\n type: WorkHydratedEvent['type'];\n /** A nonempty, short-lived reference resolved by the hydrate_event handler. */\n hydrateRef: string;\n /** Normalized comment content must not accompany a reference. */\n comment?: never;\n /** Normalized status content must not accompany a reference. */\n status?: never;\n}\n\n/** Complete normalized content or an opaque reference, with stable retry identity. */\nexport type WorkEvent =\n | (WorkHydratedEvent & { hydrateRef?: never })\n | WorkHydrationReferenceEvent;\n\n/** Install-specific delivery values provisioned through work configure. */\nexport interface SendWorkEventOptions {\n /** The exact provisioned callback URL; no production default is supplied. */\n callbackUrl: string;\n /** The per-install work-event signing secret provisioned with the callback. */\n secret: string;\n /** A transport for tests or a proxy; defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nfunction nonempty(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction validEvent(event: WorkEvent): boolean {\n const type = readText(event, 'type');\n if (\n !['comment.created', 'status.changed', 'item.deleted'].includes(type ?? '')\n )\n return false;\n if (\n !['externalItemId', 'providerEventId', 'occurredAt', 'dedupeKey'].every(\n key => nonempty(readUnknown(event, key)),\n )\n )\n return false;\n\n const reference = readUnknown(event, 'hydrateRef');\n const comment = readUnknown(event, 'comment');\n const status = readUnknown(event, 'status');\n if (reference !== undefined)\n return nonempty(reference) && comment === undefined && status === undefined;\n\n if (type === 'item.deleted')\n return comment === undefined && status === undefined;\n if (type === 'status.changed') {\n const normalized = readRecord(event, 'status');\n return (\n comment === undefined &&\n nonempty(normalized.id) &&\n nonempty(normalized.label) &&\n typeof normalized.stage === 'string' &&\n ['open', 'in_progress', 'done'].includes(normalized.stage)\n );\n }\n\n const normalized = readRecord(event, 'comment');\n const author = readRecord(normalized, 'author');\n return (\n status === undefined &&\n nonempty(normalized.externalCommentId) &&\n typeof normalized.body === 'string' &&\n nonempty(normalized.createdAt) &&\n nonempty(author.id) &&\n nonempty(author.displayName)\n );\n}\n\n/**\n * Sends one provider work event to the callback provisioned for this install.\n *\n * @remarks\n * Pass the callbackUrl and secret received through configure unchanged. The\n * event's required dedupeKey identifies the logical provider signal and must be\n * reused on retries. Complete normalized content and an opaque hydrateRef are\n * mutually exclusive. The exact serialized UTF-8 body is signed with HMAC-SHA-256.\n * This callback is independent of declared alert and banner webhooks.\n */\nexport async function sendWorkEvent(\n event: WorkEvent,\n options: SendWorkEventOptions,\n): Promise<void> {\n if (!validEvent(event))\n throw new TypeError(\n 'Invalid work event: provide complete normalized content or a nonempty hydrateRef, with routing and identity fields.',\n );\n if (!nonempty(options.callbackUrl))\n throw new TypeError(\n 'A work event requires the callbackUrl provisioned through configure.',\n );\n\n const body = JSON.stringify(event);\n const signature = await signWebhook(options.secret, body);\n const response = await (options.fetch ?? fetch)(options.callbackUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n let rejection: string | null = null;\n try {\n rejection = readText(readRecord(await response.json(), 'error'), 'code');\n } catch {\n // Proxies may return a non-JSON rejection body.\n }\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for work event ${event.type}. Check the callback URL and per-install work-event signing secret provisioned through configure.`,\n response.status,\n );\n }\n}\n"],"mappings":"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","names":["normalized"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/errors.ts"],"sourcesContent":["/** Every code a `TapError` the SDK raises carries. */\nexport type TapErrorCode =\n | 'TAP_OUTSIDE_HOST'\n | 'TAP_SCOPE_MISSING'\n | 'TAP_UNKNOWN_COLLECTION'\n | 'TAP_UNKNOWN_PROCEDURE'\n | 'TAP_NO_PORTAL'\n | 'TAP_NO_QUERY_CLIENT'\n | 'TAP_MANIFEST_INVALID'\n | 'TAP_ENTRY_MISSING'\n | 'TAP_STYLES_UNRESOLVED'\n | 'TAP_SCHEMA_UNRESOLVED'\n | 'TAP_TOKEN_MISSING'\n | 'TAP_TOKEN_INVALID'\n | 'TAP_TOKEN_AUDIENCE'\n | 'TAP_EVENT_ID_MISSING'\n | 'TAP_BODY_INVALID'\n | 'TAP_BODY_TOO_LARGE'\n | 'TAP_ROUTE_UNKNOWN'\n | 'TAP_HANDLER_MISSING'\n | 'TAP_INTERNAL_ERROR'\n | 'TAP_WEBHOOK_REJECTED'\n | 'TAP_TEST_TARGET_INVALID';\n\n/**\n * The same codes as `TapErrorCode`, as an array to iterate or check membership\n * against at runtime.\n */\nexport const TAP_ERROR_CODES: readonly TapErrorCode[] = [\n 'TAP_OUTSIDE_HOST',\n 'TAP_SCOPE_MISSING',\n 'TAP_UNKNOWN_COLLECTION',\n 'TAP_UNKNOWN_PROCEDURE',\n 'TAP_NO_PORTAL',\n 'TAP_NO_QUERY_CLIENT',\n 'TAP_MANIFEST_INVALID',\n 'TAP_ENTRY_MISSING',\n 'TAP_STYLES_UNRESOLVED',\n 'TAP_SCHEMA_UNRESOLVED',\n 'TAP_TOKEN_MISSING',\n 'TAP_TOKEN_INVALID',\n 'TAP_TOKEN_AUDIENCE',\n 'TAP_EVENT_ID_MISSING',\n 'TAP_BODY_INVALID',\n 'TAP_BODY_TOO_LARGE',\n 'TAP_ROUTE_UNKNOWN',\n 'TAP_HANDLER_MISSING',\n 'TAP_INTERNAL_ERROR',\n 'TAP_WEBHOOK_REJECTED',\n 'TAP_TEST_TARGET_INVALID',\n];\n\nconst CODE_SET = new Set<string>(TAP_ERROR_CODES);\n\n/**\n * The error the SDK and the host raise when a call cannot be served at all.\n *\n * @remarks\n * The SDK throws it for a mount outside the host (`TAP_OUTSIDE_HOST`), a\n * collection or procedure the manifest does not declare\n * (`TAP_UNKNOWN_COLLECTION`, `TAP_UNKNOWN_PROCEDURE`), a missing portal or query\n * client, a token the server rejected, and a misused testing helper. The host\n * turns a refused read or write into `TAP_SCOPE_MISSING`. Branch on `code`, which\n * is stable; the message is prose and changes. An error your own server raised is\n * a `TapServerError` instead.\n *\n * @example\n * ```tsx\n * import { TapError, useTapQuery } from '@tappify/extension-sdk';\n * import { ErrorState } from '@tappify/extension-sdk/ui';\n *\n * function Revenue() {\n * const revenue = useTapQuery({\n * kind: 'revenue',\n * range: { from: '2026-09-01', to: '2026-09-08' },\n * });\n * if (TapError.is(revenue.error) && revenue.error.code === 'TAP_SCOPE_MISSING') {\n * return <ErrorState title=\"Revenue is not shared with this extension\" />;\n * }\n * return <span>{revenue.data?.mrr ?? 0}</span>;\n * }\n * ```\n */\nexport class TapError extends Error {\n readonly code: TapErrorCode;\n\n constructor(code: TapErrorCode, message: string) {\n super(message);\n this.name = 'TapError';\n this.code = code;\n }\n\n /**\n * Narrows an unknown value to a `TapError`, by name and by a code it\n * recognises, so it holds across module instances.\n */\n static is(value: unknown): value is TapError {\n return (\n value instanceof Error &&\n value.name === 'TapError' &&\n 'code' in value &&\n typeof value.code === 'string' &&\n CODE_SET.has(value.code)\n );\n }\n}\n\n/**\n * The error a vendor server throws to answer a Tappify call with a code and a\n * message the owner sees.\n *\n * @remarks\n * `createTappifyHandler` catches it and answers `{ error: { code, message } }`\n * with `status`, or 400 when no status was given; the host relays both to the\n * calling mount, where they arrive as the `error` of `useTapServer`. Pick a code\n * of your own and keep it stable — the SDK's own codes are `SERVER_ERROR_CODES` —\n * and write the message for the owner, who reads it on screen.\n *\n * @example\n * ```ts\n * import { TapServerError } from '@tappify/extension-sdk/server';\n *\n * function assertRange(days: number) {\n * if (days > 0) return;\n * throw new TapServerError(\n * 'RANGE_TOO_SHORT',\n * 'getSummary needs a range of at least one day. Widen the date picker, then retry.',\n * 400,\n * );\n * }\n * ```\n */\nexport class TapServerError extends Error {\n readonly code: string;\n readonly status: number | undefined;\n\n constructor(code: string, message: string, status?: number) {\n super(message);\n this.name = 'TapServerError';\n this.code = code;\n this.status = status;\n }\n\n /** The wire body the handler answers with, without the status. */\n toJSON(): { error: { code: string; message: string } } {\n return { error: { code: this.code, message: this.message } };\n }\n\n /**\n * Narrows an unknown value to a `TapServerError` by name and by carrying a\n * string `code`, so it holds across module instances.\n */\n static is(value: unknown): value is TapServerError {\n return (\n value instanceof Error &&\n value.name === 'TapServerError' &&\n 'code' in value &&\n typeof value.code === 'string'\n );\n }\n}\n"],"mappings":";AA4BO,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,WAAW,IAAI,IAAY,eAAe;AA+BzC,IAAM,WAAN,cAAuB,MAAM;AAAA,EAGlC,YAAY,MAAoB,SAAiB;AAC/C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,GAAG,OAAmC;AAC3C,WACE,iBAAiB,SACjB,MAAM,SAAS,cACf,UAAU,SACV,OAAO,MAAM,SAAS,YACtB,SAAS,IAAI,MAAM,IAAI;AAAA,EAE3B;AACF;AA2BO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAIxC,YAAY,MAAc,SAAiB,QAAiB;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,SAAuD;AACrD,WAAO,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,SAAS,KAAK,QAAQ,EAAE;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,GAAG,OAAyC;AACjD,WACE,iBAAiB,SACjB,MAAM,SAAS,oBACf,UAAU,SACV,OAAO,MAAM,SAAS;AAAA,EAE1B;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TapContext
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QA5AL3VZ.mjs";
|
|
4
4
|
|
|
5
5
|
// src/host/provider.tsx
|
|
6
6
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
@@ -23,4 +23,4 @@ export {
|
|
|
23
23
|
TapHostProvider,
|
|
24
24
|
createHostQueryClient
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=chunk-
|
|
26
|
+
//# sourceMappingURL=chunk-RBIQT75L.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/host/provider.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport type { ReactElement, ReactNode } from 'react';\nimport { TapContext } from '../client/context';\nimport type { Tap } from '../client/types';\n\nexport interface TapHostProviderProps {\n tap: Tap;\n children: ReactNode;\n /**\n * A host that already renders a QueryClientProvider leaves this out; a\n * standalone host such as the local preview passes one from\n * `createHostQueryClient()` so the data hooks find a client.\n */\n queryClient?: QueryClient;\n}\n\nexport function TapHostProvider({\n tap,\n children,\n queryClient,\n}: TapHostProviderProps): ReactElement {\n const provided = (\n <TapContext.Provider value={tap}>{children}</TapContext.Provider>\n );\n\n return queryClient === undefined ? (\n provided\n ) : (\n <QueryClientProvider client={queryClient}>{provided}</QueryClientProvider>\n );\n}\n\n/** The query client a standalone host hands to `TapHostProvider`; reads never retry. */\nexport function createHostQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: { queries: { retry: false } },\n });\n}\n"],"mappings":";;;;;AAAA,SAAS,aAAa,2BAA2B;AAsB7C;AANG,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,QAAM,WACJ,oBAAC,WAAW,UAAX,EAAoB,OAAO,KAAM,UAAS;AAG7C,SAAO,gBAAgB,SACrB,WAEA,oBAAC,uBAAoB,QAAQ,aAAc,oBAAS;AAExD;AAGO,SAAS,wBAAqC;AACnD,SAAO,IAAI,YAAY;AAAA,IACrB,gBAAgB,EAAE,SAAS,EAAE,OAAO,MAAM,EAAE;AAAA,EAC9C,CAAC;AACH;","names":[]}
|
|
@@ -35,6 +35,13 @@ var SCOPES = [
|
|
|
35
35
|
requiresSecurityReview: false,
|
|
36
36
|
requiresJustification: false
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
key: "review.threads:read",
|
|
40
|
+
label: "Read Review threads",
|
|
41
|
+
description: "Review threads, comments, screenshot descriptors, build context and safe device context",
|
|
42
|
+
requiresSecurityReview: false,
|
|
43
|
+
requiresJustification: false
|
|
44
|
+
},
|
|
38
45
|
{
|
|
39
46
|
key: "crashes:read",
|
|
40
47
|
label: "Read crash data",
|
|
@@ -108,7 +115,7 @@ var SCOPES = [
|
|
|
108
115
|
{
|
|
109
116
|
key: "work:sync",
|
|
110
117
|
label: "Sync work items",
|
|
111
|
-
description: "
|
|
118
|
+
description: "Sync comments and status on created work items",
|
|
112
119
|
requiresSecurityReview: false,
|
|
113
120
|
requiresJustification: true
|
|
114
121
|
},
|
|
@@ -299,4 +306,4 @@ export {
|
|
|
299
306
|
findTable,
|
|
300
307
|
slotsForPage
|
|
301
308
|
};
|
|
302
|
-
//# sourceMappingURL=chunk-
|
|
309
|
+
//# sourceMappingURL=chunk-SGCYEEXD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/manifest/constants.ts"],"sourcesContent":["import type { ToolDeclaration } from './types';\n\nexport const SCOPES = [\n {\n key: 'ui:render',\n label: 'Render UI',\n description:\n 'Render the declared pages, tabs, widgets, row actions and settings panel, and open chat with a visible prompt',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'projects:read',\n label: 'Read the project',\n description: 'Project name, platforms and store identity',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'analytics:read',\n label: 'Read analytics',\n description: 'Downloads, impressions, page views and conversion series',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'store.metadata:read',\n label: 'Read store metadata',\n description: 'Listing metadata, keyword set and keyword positions',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'reviews:read',\n label: 'Read store reviews',\n description: 'Review text, ratings and replies',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'review.threads:read',\n label: 'Read Review threads',\n description:\n 'Review threads, comments, screenshot descriptors, build context and safe device context',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'crashes:read',\n label: 'Read crash data',\n description: 'Crash-free rate and issue counts',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'revenue:read',\n label: 'Read revenue',\n description: 'MRR, revenue series and refund counts',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'metrics:write',\n label: 'Write connector metrics',\n description:\n 'Write the metrics this extension declares into the metrics store',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'alerts:write',\n label: 'Raise alerts and banners',\n description:\n 'Turn declared webhooks into alerts and banners, at most three a day per project',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'insights:write',\n label: 'Post insights',\n description: 'Post insights to Home and to chat',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'ai:tools',\n label: 'Add assistant tools',\n description: 'Offer tools and mentions to the assistant',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'ai:actions',\n label: 'Run assistant actions',\n description: 'Run declared actions, each behind the approval card',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'store.metadata:write',\n label: 'Propose store metadata changes',\n description: 'Propose listing changes through a Tappify approval',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'autopilot:trigger',\n label: 'Trigger automated store actions',\n description: 'Start automated store actions on the owner’s behalf',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'work:create',\n label: 'Create work items',\n description: 'Create issues, pages or messages in the vendor’s system',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'work:sync',\n label: 'Sync work items',\n description: 'Sync comments and status on created work items',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'storage:write',\n label: 'Use hosted storage',\n description:\n 'Read and write this extension’s own hosted storage collections',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'messaging:send',\n label: 'Send messages to end users',\n description:\n 'Send messages or push notifications to the owner’s end users through owner-supplied credentials',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'ai:skills',\n label: 'Shape the assistant',\n description:\n 'Add skills, prompt templates and context providers that shape the assistant’s behaviour',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n] as const;\n\nexport type ScopeDefinition = (typeof SCOPES)[number];\n/** Every scope an extension can ask for under `scopes` in its manifest. */\nexport type ScopeKey = ScopeDefinition['key'];\n\nexport const SCOPE_KEYS: readonly ScopeKey[] = SCOPES.map(scope => scope.key);\n\nexport const SLOTS = [\n 'kpi-row',\n 'insights',\n 'sidebar',\n 'below-chart',\n 'below-list',\n] as const;\n/** The anchors on a host page a widget can be declared at. */\nexport type SlotId = (typeof SLOTS)[number];\n\nexport const CHARTS = [\n 'installs-activity',\n 'conversion',\n 'release-cadence',\n] as const;\nexport type HostChart = (typeof CHARTS)[number];\n\nexport const PAGES = [\n {\n key: 'overview',\n label: 'Home',\n route: '/projects/:id/overview',\n slots: ['kpi-row', 'insights', 'sidebar'],\n charts: ['installs-activity'],\n tabs: true,\n banners: true,\n },\n {\n key: 'analytics',\n label: 'Analytics',\n route: '/projects/:id/analytics',\n slots: ['kpi-row', 'below-chart', 'sidebar'],\n charts: ['installs-activity', 'conversion'],\n tabs: true,\n banners: true,\n },\n {\n key: 'deployments',\n label: 'Deployments',\n route: '/projects/:id/deployments',\n slots: ['sidebar', 'below-list'],\n charts: ['release-cadence'],\n tabs: true,\n banners: false,\n },\n {\n key: 'ai_chat',\n label: 'Assistant',\n route: 'chat',\n slots: [],\n charts: [],\n tabs: false,\n banners: false,\n },\n] as const;\n\nexport type PageDefinition = (typeof PAGES)[number];\n/** The host pages a contribution can attach a tab, widget or banner to. */\nexport type HostPage = PageDefinition['key'];\n\nexport const PAGE_KEYS: readonly HostPage[] = PAGES.map(page => page.key);\n\nexport const TABLES = [\n { key: 'analytics.keywords', label: 'Keywords' },\n { key: 'analytics.reviews', label: 'Reviews' },\n { key: 'deployments.releases', label: 'Releases' },\n { key: 'deployments.builds', label: 'Builds' },\n] as const;\n\nexport type TableDefinition = (typeof TABLES)[number];\nexport type HostTable = TableDefinition['key'];\n\nexport const TABLE_KEYS: readonly HostTable[] = TABLES.map(table => table.key);\n\nexport const KINDS = [\n 'page',\n 'tab',\n 'widget',\n 'series',\n 'banner',\n 'rowAction',\n 'marker',\n 'settings',\n 'storage',\n 'connector',\n 'webhook',\n 'tool',\n 'mention',\n 'action',\n 'knowledge',\n 'skill',\n 'prompt',\n 'context',\n 'work',\n] as const;\nexport type ContributionKind = (typeof KINDS)[number];\n\nexport const CATEGORIES = [\n 'market_data',\n 'subscriptions',\n 'product_analytics',\n 'crashes',\n 'attribution',\n 'experiments',\n 'messaging',\n 'session_replay',\n 'localization',\n 'design',\n 'ci_cd',\n 'trackers',\n 'support',\n 'chat',\n 'ad_monetization',\n 'warehouse',\n 'compliance',\n 'additional_stores',\n] as const;\nexport type ExtensionCategory = (typeof CATEGORIES)[number];\n\nexport const EVENTS = [\n 'release.shipped',\n 'metadata.changed',\n 'keyword.set_changed',\n 'screenshots.updated',\n 'price.changed',\n 'featuring.started',\n 'score.changed',\n 'incident.opened',\n 'incident.resolved',\n 'playbook.step_approved',\n 'review.thread_opened',\n 'review.thread_resolved',\n 'approval.requested',\n 'digest.sent',\n 'install.created',\n 'install.paused',\n 'install.resumed',\n 'install.revoked',\n 'install.token_rotated',\n 'scopes.changed',\n 'settings.changed',\n] as const;\n/** Every event Tappify emits, which a mount or a server can subscribe to. */\nexport type HostEventName = (typeof EVENTS)[number];\n\nexport const SERVED_SDK_MAJORS: readonly number[] = [2];\n\n/** The `kind` of every read `tap.data.query` accepts, one per scope it needs. */\nexport type DataQueryKind =\n | 'project'\n | 'series'\n | 'keywords'\n | 'listing'\n | 'reviews'\n | 'crashes'\n | 'revenue';\n\nexport const QUERY_SCOPES: Record<DataQueryKind, ScopeKey> = {\n project: 'projects:read',\n series: 'analytics:read',\n keywords: 'store.metadata:read',\n listing: 'store.metadata:read',\n reviews: 'reviews:read',\n crashes: 'crashes:read',\n revenue: 'revenue:read',\n};\n\n/**\n * The keys a tool's answer carries for each `returns` kind it may declare.\n * `validateToolResponse`, `tappify extension doctor` and the host all read\n * this one table, so a wrong body fails the same way wherever it is checked.\n */\nexport const CARD_KEYS: Record<ToolDeclaration['returns'], string[]> = {\n value: ['label', 'value'],\n series: ['label', 'points'],\n table: ['columns', 'rows'],\n list: ['items'],\n comparison: ['label', 'left', 'right'],\n};\n\nexport const findScope = (key: string): ScopeDefinition | undefined =>\n SCOPES.find(scope => scope.key === key);\n\nexport const findPage = (key: string): PageDefinition | undefined =>\n PAGES.find(page => page.key === key);\n\nexport const findTable = (key: string): TableDefinition | undefined =>\n TABLES.find(table => table.key === key);\n\nexport const slotsForPage = (page: string): readonly SlotId[] =>\n findPage(page)?.slots ?? [];\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useTap
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QA5AL3VZ.mjs";
|
|
4
4
|
import {
|
|
5
5
|
TapError
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QXD7WVKK.mjs";
|
|
7
7
|
|
|
8
8
|
// src/client/hooks.ts
|
|
9
9
|
import { useCallback, useSyncExternalStore } from "react";
|
|
@@ -247,4 +247,4 @@ export {
|
|
|
247
247
|
useTapServer,
|
|
248
248
|
useTapStorage
|
|
249
249
|
};
|
|
250
|
-
//# sourceMappingURL=chunk-
|
|
250
|
+
//# sourceMappingURL=chunk-SGEYDV3K.mjs.map
|