showpane 0.4.1 → 0.4.2

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.
Files changed (106) hide show
  1. package/README.md +14 -1
  2. package/bundle/meta/scaffold-manifest.json +73 -0
  3. package/bundle/scaffold/VERSION +1 -0
  4. package/bundle/scaffold/__dot__env.example +24 -0
  5. package/bundle/scaffold/__dot__gitignore +41 -0
  6. package/bundle/scaffold/docker/Caddyfile +3 -0
  7. package/bundle/scaffold/docker/Dockerfile +30 -0
  8. package/bundle/scaffold/docker-compose.yml +53 -0
  9. package/bundle/scaffold/next.config.ts +20 -0
  10. package/bundle/scaffold/package-lock.json +5843 -0
  11. package/bundle/scaffold/package.json +42 -0
  12. package/bundle/scaffold/postcss.config.js +6 -0
  13. package/bundle/scaffold/prisma/migrations/20260408000000_init/migration.sql +143 -0
  14. package/bundle/scaffold/prisma/migrations/20260408010000_add_visitor_tracking/migration.sql +6 -0
  15. package/bundle/scaffold/prisma/migrations/20260409040000_add_portal_file_checksum/migration.sql +2 -0
  16. package/bundle/scaffold/prisma/migrations/migration_lock.toml +3 -0
  17. package/bundle/scaffold/prisma/schema.local.prisma +131 -0
  18. package/bundle/scaffold/prisma/schema.prisma +128 -0
  19. package/bundle/scaffold/prisma/seed.ts +49 -0
  20. package/bundle/scaffold/public/example-avatar.svg +4 -0
  21. package/bundle/scaffold/public/example-logo.svg +4 -0
  22. package/bundle/scaffold/public/robots.txt +2 -0
  23. package/bundle/scaffold/scripts/backup.sh +19 -0
  24. package/bundle/scaffold/scripts/e2e-verify.sh +487 -0
  25. package/bundle/scaffold/scripts/prisma-db-push.mjs +7 -0
  26. package/bundle/scaffold/scripts/prisma-generate.mjs +3 -0
  27. package/bundle/scaffold/scripts/prisma-schema.mjs +74 -0
  28. package/bundle/scaffold/scripts/restore.sh +31 -0
  29. package/bundle/scaffold/src/__tests__/client-portals.test.ts +80 -0
  30. package/bundle/scaffold/src/__tests__/portal-contracts.test.ts +32 -0
  31. package/bundle/scaffold/src/app/(portal)/client/[slug]/page.tsx +79 -0
  32. package/bundle/scaffold/src/app/(portal)/client/[slug]/s/[token]/route.ts +22 -0
  33. package/bundle/scaffold/src/app/(portal)/client/example/example-client.tsx +372 -0
  34. package/bundle/scaffold/src/app/(portal)/client/example/page.tsx +5 -0
  35. package/bundle/scaffold/src/app/(portal)/client/layout.tsx +7 -0
  36. package/bundle/scaffold/src/app/(portal)/client/page.tsx +18 -0
  37. package/bundle/scaffold/src/app/api/client-auth/route.ts +82 -0
  38. package/bundle/scaffold/src/app/api/client-auth/share/route.ts +30 -0
  39. package/bundle/scaffold/src/app/api/client-events/route.ts +87 -0
  40. package/bundle/scaffold/src/app/api/client-files/[...path]/route.ts +80 -0
  41. package/bundle/scaffold/src/app/api/client-files/client-upload/route.ts +118 -0
  42. package/bundle/scaffold/src/app/api/client-files/route.ts +37 -0
  43. package/bundle/scaffold/src/app/api/client-files/upload/route.ts +131 -0
  44. package/bundle/scaffold/src/app/api/health/route.ts +19 -0
  45. package/bundle/scaffold/src/app/globals.css +7 -0
  46. package/bundle/scaffold/src/app/layout.tsx +25 -0
  47. package/bundle/scaffold/src/app/page.tsx +171 -0
  48. package/bundle/scaffold/src/components/portal-login.tsx +169 -0
  49. package/bundle/scaffold/src/components/portal-shell.tsx +373 -0
  50. package/bundle/scaffold/src/lib/abuse-controls.ts +43 -0
  51. package/bundle/scaffold/src/lib/branding.ts +50 -0
  52. package/bundle/scaffold/src/lib/client-auth.ts +98 -0
  53. package/bundle/scaffold/src/lib/client-portals.ts +134 -0
  54. package/bundle/scaffold/src/lib/control-plane.ts +100 -0
  55. package/bundle/scaffold/src/lib/db.ts +7 -0
  56. package/bundle/scaffold/src/lib/files.ts +124 -0
  57. package/bundle/scaffold/src/lib/load-app-env.ts +42 -0
  58. package/bundle/scaffold/src/lib/portal-contracts.ts +69 -0
  59. package/bundle/scaffold/src/lib/prisma-client.ts +5 -0
  60. package/bundle/scaffold/src/lib/runtime-state.ts +69 -0
  61. package/bundle/scaffold/src/lib/storage.ts +204 -0
  62. package/bundle/scaffold/src/lib/token.ts +186 -0
  63. package/bundle/scaffold/src/lib/utils.ts +6 -0
  64. package/bundle/scaffold/src/middleware.ts +61 -0
  65. package/bundle/scaffold/tailwind.config.ts +15 -0
  66. package/bundle/scaffold/tests/__dot__gitkeep +0 -0
  67. package/bundle/scaffold/tsconfig.json +23 -0
  68. package/bundle/scaffold/vitest.config.ts +13 -0
  69. package/bundle/toolchain/VERSION +1 -0
  70. package/bundle/toolchain/bin/check-slug.ts +59 -0
  71. package/bundle/toolchain/bin/create-deploy-bundle.ts +93 -0
  72. package/bundle/toolchain/bin/create-portal.ts +71 -0
  73. package/bundle/toolchain/bin/delete-portal.ts +48 -0
  74. package/bundle/toolchain/bin/export-file-manifest.ts +84 -0
  75. package/bundle/toolchain/bin/export-runtime-state.ts +90 -0
  76. package/bundle/toolchain/bin/generate-share-link.ts +68 -0
  77. package/bundle/toolchain/bin/list-portals.ts +53 -0
  78. package/bundle/toolchain/bin/materialize-file.ts +35 -0
  79. package/bundle/toolchain/bin/query-analytics.ts +88 -0
  80. package/bundle/toolchain/bin/rotate-credentials.ts +57 -0
  81. package/bundle/toolchain/bin/showpane-config +63 -0
  82. package/bundle/toolchain/bin/tsconfig.json +13 -0
  83. package/bundle/toolchain/skills/VERSION +1 -0
  84. package/bundle/toolchain/skills/portal-analytics/SKILL.md +263 -0
  85. package/bundle/toolchain/skills/portal-create/SKILL.md +341 -0
  86. package/bundle/toolchain/skills/portal-credentials/SKILL.md +274 -0
  87. package/bundle/toolchain/skills/portal-delete/SKILL.md +265 -0
  88. package/bundle/toolchain/skills/portal-deploy/SKILL.md +721 -0
  89. package/bundle/toolchain/skills/portal-dev/SKILL.md +301 -0
  90. package/bundle/toolchain/skills/portal-list/SKILL.md +253 -0
  91. package/bundle/toolchain/skills/portal-onboard/SKILL.md +277 -0
  92. package/bundle/toolchain/skills/portal-preview/SKILL.md +257 -0
  93. package/bundle/toolchain/skills/portal-setup/SKILL.md +309 -0
  94. package/bundle/toolchain/skills/portal-share/SKILL.md +234 -0
  95. package/bundle/toolchain/skills/portal-status/SKILL.md +268 -0
  96. package/bundle/toolchain/skills/portal-update/SKILL.md +348 -0
  97. package/bundle/toolchain/skills/portal-upgrade/SKILL.md +235 -0
  98. package/bundle/toolchain/skills/portal-verify/SKILL.md +265 -0
  99. package/bundle/toolchain/skills/shared/bin/check-portal-guard.sh +49 -0
  100. package/bundle/toolchain/skills/shared/platform-constraints.md +33 -0
  101. package/bundle/toolchain/skills/shared/preamble.md +137 -0
  102. package/bundle/toolchain/templates/consulting/consulting-client.tsx +205 -0
  103. package/bundle/toolchain/templates/onboarding/onboarding-client.tsx +237 -0
  104. package/bundle/toolchain/templates/sales-followup/sales-followup-client.tsx +283 -0
  105. package/dist/index.js +873 -166
  106. package/package.json +3 -2
@@ -0,0 +1,90 @@
1
+ import { PrismaClient } from "@/lib/prisma-client";
2
+
3
+ function fail(message: string): never {
4
+ console.error(JSON.stringify({ ok: false, error: message }));
5
+ process.exit(1);
6
+ }
7
+
8
+ type Args = {
9
+ orgId?: string;
10
+ orgSlug?: string;
11
+ };
12
+
13
+ function parseArgs(argv: string[]): Args {
14
+ const getArg = (flag: string) => {
15
+ const index = argv.indexOf(flag);
16
+ return index !== -1 ? argv[index + 1] : undefined;
17
+ };
18
+
19
+ return {
20
+ orgId: getArg("--org-id"),
21
+ orgSlug: getArg("--org-slug"),
22
+ };
23
+ }
24
+
25
+ async function main() {
26
+ const args = process.argv.slice(2);
27
+
28
+ if (args.includes("--help")) {
29
+ console.log("Usage: export-runtime-state [--org-id <orgId>] [--org-slug <slug>]");
30
+ console.log("Exports the local portal runtime state for cloud deploy sync.");
31
+ process.exit(0);
32
+ }
33
+
34
+ const { orgId, orgSlug } = parseArgs(args);
35
+ const prisma = new PrismaClient();
36
+
37
+ try {
38
+ const organization = orgId
39
+ ? await prisma.organization.findUnique({ where: { id: orgId } })
40
+ : orgSlug
41
+ ? await prisma.organization.findUnique({ where: { slug: orgSlug } })
42
+ : await prisma.organization.findFirst({ orderBy: { createdAt: "asc" } });
43
+
44
+ if (!organization) {
45
+ fail("No organization found");
46
+ }
47
+
48
+ const portals = await prisma.clientPortal.findMany({
49
+ where: { organizationId: organization.id },
50
+ orderBy: { createdAt: "asc" },
51
+ select: {
52
+ slug: true,
53
+ companyName: true,
54
+ logoUrl: true,
55
+ username: true,
56
+ passwordHash: true,
57
+ credentialVersion: true,
58
+ isActive: true,
59
+ lastUpdated: true,
60
+ },
61
+ });
62
+
63
+ console.log(JSON.stringify({
64
+ ok: true,
65
+ organization: {
66
+ id: organization.id,
67
+ slug: organization.slug,
68
+ name: organization.name,
69
+ logoUrl: organization.logoUrl,
70
+ primaryColor: organization.primaryColor,
71
+ portalLabel: organization.portalLabel,
72
+ websiteUrl: organization.websiteUrl,
73
+ contactName: organization.contactName,
74
+ contactTitle: organization.contactTitle,
75
+ contactEmail: organization.contactEmail,
76
+ contactPhone: organization.contactPhone,
77
+ contactAvatar: organization.contactAvatar,
78
+ supportEmail: organization.supportEmail,
79
+ customDomain: organization.customDomain,
80
+ },
81
+ portals,
82
+ }));
83
+ } finally {
84
+ await prisma.$disconnect();
85
+ }
86
+ }
87
+
88
+ main().catch((error) => {
89
+ fail(String(error));
90
+ });
@@ -0,0 +1,68 @@
1
+ import { PrismaClient } from "@/lib/prisma-client";
2
+ import { buildAndSignToken, SHARE_TOKEN_MAX_AGE_SECONDS } from "@/lib/token";
3
+
4
+ function fail(message: string): never {
5
+ console.error(JSON.stringify({ ok: false, error: message }));
6
+ process.exit(1);
7
+ }
8
+
9
+ function getArg(args: string[], flag: string): string | undefined {
10
+ const idx = args.indexOf(flag);
11
+ return idx !== -1 ? args[idx + 1] : undefined;
12
+ }
13
+
14
+ async function main() {
15
+ const args = process.argv.slice(2);
16
+
17
+ if (args.includes("--help")) {
18
+ console.log("Usage: generate-share-link --slug <slug> --org-id <orgId> [--base-url <url>]");
19
+ console.log("Generates a reusable share link for a portal.");
20
+ process.exit(0);
21
+ }
22
+
23
+ const slug = getArg(args, "--slug");
24
+ const orgId = getArg(args, "--org-id");
25
+ const baseUrl = getArg(args, "--base-url")
26
+ ?? process.env.NEXT_PUBLIC_APP_URL
27
+ ?? "http://localhost:3000";
28
+
29
+ if (!slug || !orgId) fail("Missing --slug or --org-id");
30
+
31
+ if (!process.env.AUTH_SECRET) fail("AUTH_SECRET not set in environment");
32
+
33
+ const prisma = new PrismaClient();
34
+ try {
35
+ const portal = await prisma.clientPortal.findUnique({
36
+ where: { organizationId_slug: { organizationId: orgId, slug } },
37
+ select: { credentialVersion: true, isActive: true },
38
+ });
39
+
40
+ if (!portal) fail(`Portal "${slug}" not found`);
41
+ if (!portal.isActive) fail(`Portal "${slug}" is inactive`);
42
+
43
+ const token = await buildAndSignToken(
44
+ orgId,
45
+ slug,
46
+ "share",
47
+ SHARE_TOKEN_MAX_AGE_SECONDS,
48
+ portal.credentialVersion
49
+ );
50
+
51
+ if (!token) fail("Failed to sign token — check AUTH_SECRET");
52
+
53
+ const shareUrl = `${baseUrl.replace(/\/$/, "")}/client/${slug}/s/${token}`;
54
+
55
+ console.log(JSON.stringify({
56
+ ok: true,
57
+ shareUrl,
58
+ expiresIn: "never",
59
+ }));
60
+ } finally {
61
+ await prisma.$disconnect();
62
+ }
63
+ }
64
+
65
+ main().catch((e) => {
66
+ console.error(JSON.stringify({ ok: false, error: String(e) }));
67
+ process.exit(1);
68
+ });
@@ -0,0 +1,53 @@
1
+ import { PrismaClient } from "@/lib/prisma-client";
2
+
3
+ function fail(message: string): never {
4
+ console.error(JSON.stringify({ ok: false, error: message }));
5
+ process.exit(1);
6
+ }
7
+
8
+ async function main() {
9
+ const args = process.argv.slice(2);
10
+
11
+ if (args.includes("--help")) {
12
+ console.log("Usage: list-portals [--org-id <orgId>]");
13
+ console.log("Lists all client portals. Defaults to first organization if --org-id omitted.");
14
+ process.exit(0);
15
+ }
16
+
17
+ const prisma = new PrismaClient();
18
+ try {
19
+ const getArg = (flag: string) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : undefined; };
20
+ let orgId = getArg("--org-id");
21
+
22
+ if (!orgId) {
23
+ const firstOrg = await prisma.organization.findFirst({ select: { id: true } });
24
+ if (!firstOrg) fail("No organizations found");
25
+ orgId = firstOrg.id;
26
+ }
27
+
28
+ const portals = await prisma.clientPortal.findMany({
29
+ where: { organizationId: orgId },
30
+ include: { organization: { select: { name: true } } },
31
+ orderBy: { createdAt: "desc" },
32
+ });
33
+
34
+ console.log(JSON.stringify({
35
+ ok: true,
36
+ portals: portals.map((p) => ({
37
+ slug: p.slug,
38
+ companyName: p.companyName,
39
+ isActive: p.isActive,
40
+ lastUpdated: p.lastUpdated,
41
+ username: p.username,
42
+ createdAt: p.createdAt.toISOString(),
43
+ })),
44
+ }));
45
+ } finally {
46
+ await prisma.$disconnect();
47
+ }
48
+ }
49
+
50
+ main().catch((e) => {
51
+ console.error(JSON.stringify({ ok: false, error: String(e) }));
52
+ process.exit(1);
53
+ });
@@ -0,0 +1,35 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readFile_ } from "@/lib/storage";
4
+
5
+ function fail(message: string): never {
6
+ console.error(JSON.stringify({ error: message }));
7
+ process.exit(1);
8
+ }
9
+
10
+ async function main() {
11
+ const args = process.argv.slice(2);
12
+ const getArg = (flag: string) => {
13
+ const index = args.indexOf(flag);
14
+ return index !== -1 ? args[index + 1] : undefined;
15
+ };
16
+
17
+ const storagePath = getArg("--storage-path");
18
+ const output = getArg("--output");
19
+
20
+ if (!storagePath || !output) {
21
+ fail("Missing --storage-path or --output");
22
+ }
23
+
24
+ const data = await readFile_(storagePath);
25
+ if (!data) {
26
+ fail(`File not found in storage: ${storagePath}`);
27
+ }
28
+
29
+ await mkdir(path.dirname(output), { recursive: true });
30
+ await writeFile(output, data);
31
+ }
32
+
33
+ main().catch((error) => {
34
+ fail(String(error));
35
+ });
@@ -0,0 +1,88 @@
1
+ import { PrismaClient } from "@/lib/prisma-client";
2
+
3
+ function fail(message: string): never {
4
+ console.error(JSON.stringify({ ok: false, error: message }));
5
+ process.exit(1);
6
+ }
7
+
8
+ function getArg(args: string[], flag: string): string | undefined {
9
+ const idx = args.indexOf(flag);
10
+ return idx !== -1 ? args[idx + 1] : undefined;
11
+ }
12
+
13
+ async function main() {
14
+ const args = process.argv.slice(2);
15
+
16
+ if (args.includes("--help")) {
17
+ console.log("Usage: query-analytics [--slug <slug>] [--days <n>] --org-id <orgId>");
18
+ console.log("Queries portal events. Omit --slug for all portals. Default --days is 30.");
19
+ process.exit(0);
20
+ }
21
+
22
+ const slug = getArg(args, "--slug");
23
+ const days = parseInt(getArg(args, "--days") ?? "30", 10);
24
+ const orgId = getArg(args, "--org-id");
25
+
26
+ if (!orgId) fail("Missing --org-id");
27
+
28
+ const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
29
+ const prisma = new PrismaClient();
30
+
31
+ try {
32
+ // Find portals in scope
33
+ const portals = await prisma.clientPortal.findMany({
34
+ where: {
35
+ organizationId: orgId,
36
+ ...(slug ? { slug } : {}),
37
+ },
38
+ select: { id: true, slug: true },
39
+ });
40
+
41
+ if (slug && portals.length === 0) fail(`Portal "${slug}" not found`);
42
+
43
+ const portalIds = portals.map((p) => p.id);
44
+
45
+ // Query events grouped by type
46
+ const events = await prisma.portalEvent.groupBy({
47
+ by: ["event", "portalId"],
48
+ where: {
49
+ portalId: { in: portalIds },
50
+ createdAt: { gte: since },
51
+ },
52
+ _count: { id: true },
53
+ });
54
+
55
+ // Get last activity
56
+ const lastEvent = await prisma.portalEvent.findFirst({
57
+ where: {
58
+ portalId: { in: portalIds },
59
+ createdAt: { gte: since },
60
+ },
61
+ orderBy: { createdAt: "desc" },
62
+ select: { createdAt: true },
63
+ });
64
+
65
+ // Aggregate counts by event type
66
+ const counts: Record<string, number> = {};
67
+ for (const e of events) {
68
+ counts[e.event] = (counts[e.event] ?? 0) + e._count.id;
69
+ }
70
+
71
+ console.log(JSON.stringify({
72
+ ok: true,
73
+ slug: slug ?? "all",
74
+ period: `${days}d`,
75
+ views: counts["portal_view"] ?? 0,
76
+ tabSwitches: counts["tab_switch"] ?? 0,
77
+ events: counts,
78
+ lastActivity: lastEvent?.createdAt.toISOString() ?? null,
79
+ }));
80
+ } finally {
81
+ await prisma.$disconnect();
82
+ }
83
+ }
84
+
85
+ main().catch((e) => {
86
+ console.error(JSON.stringify({ ok: false, error: String(e) }));
87
+ process.exit(1);
88
+ });
@@ -0,0 +1,57 @@
1
+ import { PrismaClient } from "@/lib/prisma-client";
2
+ import bcrypt from "bcryptjs";
3
+ import crypto from "node:crypto";
4
+
5
+ function fail(message: string): never {
6
+ console.error(JSON.stringify({ ok: false, error: message }));
7
+ process.exit(1);
8
+ }
9
+
10
+ async function main() {
11
+ const args = process.argv.slice(2);
12
+
13
+ if (args.includes("--help")) {
14
+ console.log("Usage: rotate-credentials --slug <slug> --org-id <orgId>");
15
+ console.log("Rotates the password for a portal. New password shown once.");
16
+ process.exit(0);
17
+ }
18
+
19
+ const getArg = (flag: string) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : undefined; };
20
+ const slug = getArg("--slug");
21
+ const orgId = getArg("--org-id");
22
+
23
+ if (!slug || !orgId) fail("Missing --slug or --org-id");
24
+
25
+ const prisma = new PrismaClient();
26
+ try {
27
+ const portal = await prisma.clientPortal.findUnique({
28
+ where: { organizationId_slug: { organizationId: orgId, slug } },
29
+ });
30
+ if (!portal) fail(`Portal "${slug}" not found`);
31
+
32
+ const password = crypto.randomBytes(16).toString("base64url");
33
+ const passwordHash = await bcrypt.hash(password, 10);
34
+
35
+ await prisma.clientPortal.update({
36
+ where: { id: portal.id },
37
+ data: {
38
+ passwordHash,
39
+ credentialVersion: crypto.randomUUID(),
40
+ },
41
+ });
42
+
43
+ console.log(JSON.stringify({
44
+ ok: true,
45
+ username: portal.username,
46
+ password,
47
+ rotated: true,
48
+ }));
49
+ } finally {
50
+ await prisma.$disconnect();
51
+ }
52
+ }
53
+
54
+ main().catch((e) => {
55
+ console.error(JSON.stringify({ ok: false, error: String(e) }));
56
+ process.exit(1);
57
+ });
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ CONFIG_DIR="${HOME}/.showpane"
5
+ CONFIG_FILE="${CONFIG_DIR}/config.json"
6
+
7
+ usage() {
8
+ echo "Usage: showpane-config <get|set> <key> [value]"
9
+ echo ""
10
+ echo "Commands:"
11
+ echo " get <key> Read a value from config"
12
+ echo " set <key> <value> Write a value to config"
13
+ echo ""
14
+ echo "Config file: ${CONFIG_FILE}"
15
+ exit 1
16
+ }
17
+
18
+ ensure_config() {
19
+ if [ ! -d "$CONFIG_DIR" ]; then
20
+ mkdir -p "$CONFIG_DIR"
21
+ fi
22
+ if [ ! -f "$CONFIG_FILE" ]; then
23
+ echo '{}' > "$CONFIG_FILE"
24
+ chmod 600 "$CONFIG_FILE"
25
+ fi
26
+ }
27
+
28
+ case "${1:-}" in
29
+ get)
30
+ [ -z "${2:-}" ] && usage
31
+ ensure_config
32
+ # Use python3 for portable JSON parsing (available on macOS + Linux)
33
+ python3 -c "
34
+ import json, sys
35
+ with open('$CONFIG_FILE') as f:
36
+ data = json.load(f)
37
+ key = '$2'
38
+ if key in data:
39
+ print(data[key])
40
+ else:
41
+ sys.exit(1)
42
+ "
43
+ ;;
44
+ set)
45
+ [ -z "${2:-}" ] || [ -z "${3:-}" ] && usage
46
+ ensure_config
47
+ python3 -c "
48
+ import json
49
+ with open('$CONFIG_FILE') as f:
50
+ data = json.load(f)
51
+ data['$2'] = '$3'
52
+ with open('$CONFIG_FILE', 'w') as f:
53
+ json.dump(data, f, indent=2)
54
+ "
55
+ chmod 600 "$CONFIG_FILE"
56
+ ;;
57
+ --help|-h)
58
+ usage
59
+ ;;
60
+ *)
61
+ usage
62
+ ;;
63
+ esac
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "esnext",
5
+ "moduleResolution": "bundler",
6
+ "resolveJsonModule": true,
7
+ "esModuleInterop": true,
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "rootDir": "."
11
+ },
12
+ "include": ["./**/*.ts"]
13
+ }
@@ -0,0 +1 @@
1
+ 1.1.0 (requires app >= 0.2.0)