@skhema/cli 0.4.8 → 0.5.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 +24 -1
- package/dist/commands/contribute.d.ts.map +1 -1
- package/dist/commands/contribute.js +188 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +5 -4
- package/dist/lib/contribute/api.d.ts +14 -0
- package/dist/lib/contribute/api.d.ts.map +1 -0
- package/dist/lib/contribute/api.js +36 -0
- package/dist/lib/contribute/embed-generator.d.ts +1 -0
- package/dist/lib/contribute/embed-generator.d.ts.map +1 -1
- package/dist/lib/contribute/embed-generator.js +6 -1
- package/dist/lib/contribute/types.d.ts +74 -0
- package/dist/lib/contribute/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ SKHEMA_API_KEY=sk_live_… npx @skhema/cli init --yes --json
|
|
|
31
31
|
future commands (never overwriting a different stored key without `--force`).
|
|
32
32
|
- **Installs skills** into every detected agent platform (idempotent — reruns
|
|
33
33
|
report `unchanged`).
|
|
34
|
-
- **Registers the MCP server** (`https://mcp
|
|
34
|
+
- **Registers the MCP server** (`https://mcp.skhema.com/mcp`, Streamable
|
|
35
35
|
HTTP) in detected clients by safely merging a dedicated config file and writing
|
|
36
36
|
a `.bak` backup — **or printing copy-paste instructions** when a client's config
|
|
37
37
|
isn't cleanly writable. `--yes` registers non-interactively; without it, `init`
|
|
@@ -160,6 +160,29 @@ skhema workspace use --clear
|
|
|
160
160
|
|
|
161
161
|
Later workspace-scoped commands read this default when `--workspace` is omitted.
|
|
162
162
|
|
|
163
|
+
## Contributor commands
|
|
164
|
+
|
|
165
|
+
Approved contributors get a `contribute` command group for generating embeds and
|
|
166
|
+
shareable links, and for inspecting their account, analytics, and payouts. Every
|
|
167
|
+
command is gated on approved-contributor status and honours `--json`.
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
skhema contribute generate embed --element-type key_challenge \
|
|
171
|
+
--content "..." --contributor-id contrib_… # HTML <skhema-element> snippet
|
|
172
|
+
skhema contribute generate link --element-type key_challenge \
|
|
173
|
+
--content "..." --contributor-id contrib_… # save + share links
|
|
174
|
+
|
|
175
|
+
skhema contribute status # approval status, ID, display name
|
|
176
|
+
skhema contribute profile # public profile (edit at contribute.skhema.com/account)
|
|
177
|
+
skhema contribute analytics --time-range 30d # embeds, loads, clicks, CTR + top content
|
|
178
|
+
skhema contribute analytics --content-hash <hash> # per-content detail with top pages
|
|
179
|
+
skhema contribute payouts # payout history (20% commission, 60-day hold)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Generated embed snippets pin the CDN to a specific `@skhema/embed` version
|
|
183
|
+
(`https://unpkg.com/@skhema/embed@<version>/dist/embed.min.js`), so a published
|
|
184
|
+
snippet renders identically forever rather than tracking `latest`.
|
|
185
|
+
|
|
163
186
|
## Configuration & storage
|
|
164
187
|
|
|
165
188
|
| What | Where |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contribute.d.ts","sourceRoot":"","sources":["../../src/commands/contribute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"contribute.d.ts","sourceRoot":"","sources":["../../src/commands/contribute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA0HnC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAskBjE"}
|
|
@@ -2,10 +2,11 @@ import fs from 'node:fs';
|
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { isApprovedContributor } from '../lib/auth/entitlements.js';
|
|
4
4
|
import { getStoredCredentials } from '../lib/auth/token-store.js';
|
|
5
|
+
import { postContributeFunction } from '../lib/contribute/api.js';
|
|
5
6
|
import { resolveComponentAuthor, resolveElementAuthor, } from '../lib/contribute/author-resolver.js';
|
|
6
7
|
import { generateComponentEmbed, generateEmbed, } from '../lib/contribute/embed-generator.js';
|
|
7
8
|
import { generateSaveComponentLink, generateSaveElementLink, publishAndGenerateComponentShareLink, publishAndGenerateElementShareLink, } from '../lib/contribute/link-generator.js';
|
|
8
|
-
import { getGlobalOptions, log, outputError, outputSuccess, } from '../lib/output.js';
|
|
9
|
+
import { getGlobalOptions, log, logHeader, logTable, outputError, outputSuccess, } from '../lib/output.js';
|
|
9
10
|
function parseElementArgs(elementArgs) {
|
|
10
11
|
return elementArgs.map((arg) => {
|
|
11
12
|
const colonIndex = arg.indexOf(':');
|
|
@@ -45,10 +46,30 @@ async function requireContributor() {
|
|
|
45
46
|
process.exit(1);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
const ANALYTICS_TIME_RANGES = ['24h', '7d', '30d', '90d'];
|
|
50
|
+
function truncate(text, max = 42) {
|
|
51
|
+
const clean = text.replace(/\s+/g, ' ').trim();
|
|
52
|
+
return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean;
|
|
53
|
+
}
|
|
54
|
+
function formatDate(iso) {
|
|
55
|
+
const date = new Date(iso);
|
|
56
|
+
return Number.isNaN(date.getTime()) ? iso : date.toISOString().slice(0, 10);
|
|
57
|
+
}
|
|
58
|
+
// payoutAmount is stored in minor units (cents) — the backend computes it as
|
|
59
|
+
// Math.round(subtotalCents * 20 / 100). Render as a major-unit decimal.
|
|
60
|
+
function formatAmount(amountCents, currency) {
|
|
61
|
+
if (amountCents === null)
|
|
62
|
+
return '—';
|
|
63
|
+
const amount = (amountCents / 100).toFixed(2);
|
|
64
|
+
return currency ? `${amount} ${currency.toUpperCase()}` : amount;
|
|
65
|
+
}
|
|
66
|
+
function isDetailAnalytics(data) {
|
|
67
|
+
return 'pages' in data;
|
|
68
|
+
}
|
|
48
69
|
export function registerContributeCommands(program) {
|
|
49
70
|
const contribute = program
|
|
50
71
|
.command('contribute')
|
|
51
|
-
.description('Contributor tools — requires approved contributor status')
|
|
72
|
+
.description('Contributor tools — embeds, links, status, profile, analytics, and payouts (requires approved contributor status)')
|
|
52
73
|
.hook('preAction', requireContributor);
|
|
53
74
|
const generate = contribute
|
|
54
75
|
.command('generate')
|
|
@@ -315,4 +336,169 @@ export function registerContributeCommands(program) {
|
|
|
315
336
|
process.exit(1);
|
|
316
337
|
}
|
|
317
338
|
});
|
|
339
|
+
contribute
|
|
340
|
+
.command('status')
|
|
341
|
+
.description('Show your contributor approval status, ID, and display name')
|
|
342
|
+
.action(async () => {
|
|
343
|
+
const opts = getGlobalOptions();
|
|
344
|
+
const spinner = opts.json || opts.quiet
|
|
345
|
+
? null
|
|
346
|
+
: ora('Fetching contributor status...').start();
|
|
347
|
+
try {
|
|
348
|
+
const status = await postContributeFunction('contributor-manage', { action: 'check-status' });
|
|
349
|
+
const profile = await postContributeFunction('contributor-manage', { action: 'get-profile' });
|
|
350
|
+
spinner?.stop();
|
|
351
|
+
if (getGlobalOptions().json) {
|
|
352
|
+
outputSuccess({ status, profile }, 'contribute status');
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const approval = status.approved
|
|
356
|
+
? 'Approved contributor'
|
|
357
|
+
: status.isContributor
|
|
358
|
+
? 'Pending approval'
|
|
359
|
+
: 'Not a contributor';
|
|
360
|
+
log(`Status: ${approval}`);
|
|
361
|
+
log(`Contributor ID: ${status.contributorId ?? profile.contributorId ?? '—'}`);
|
|
362
|
+
log(`Display name: ${profile.resolvedDisplayName}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
spinner?.stop();
|
|
367
|
+
outputError(error instanceof Error ? error.message : 'Failed to fetch status', 'contribute status');
|
|
368
|
+
process.exit(1);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
contribute
|
|
372
|
+
.command('profile')
|
|
373
|
+
.description('Show your public contributor profile (read-only)')
|
|
374
|
+
.action(async () => {
|
|
375
|
+
const opts = getGlobalOptions();
|
|
376
|
+
const spinner = opts.json || opts.quiet ? null : ora('Fetching profile...').start();
|
|
377
|
+
try {
|
|
378
|
+
const profile = await postContributeFunction('contributor-manage', { action: 'get-profile' });
|
|
379
|
+
spinner?.stop();
|
|
380
|
+
if (getGlobalOptions().json) {
|
|
381
|
+
outputSuccess(profile, 'contribute profile');
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
log(`Contributor ID: ${profile.contributorId}`);
|
|
385
|
+
log(`Display name: ${profile.resolvedDisplayName}`);
|
|
386
|
+
log(`Name preference: ${profile.displayNamePreference}`);
|
|
387
|
+
log(`Custom name: ${profile.displayName ?? '—'}`);
|
|
388
|
+
log(`Bio: ${profile.bio ?? '—'}`);
|
|
389
|
+
log(`Website: ${profile.publicWebsiteUrl ?? '—'}`);
|
|
390
|
+
log('');
|
|
391
|
+
log('Edit your profile at https://contribute.skhema.com/account');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
spinner?.stop();
|
|
396
|
+
outputError(error instanceof Error ? error.message : 'Failed to fetch profile', 'contribute profile');
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
contribute
|
|
401
|
+
.command('analytics')
|
|
402
|
+
.description('Show embed analytics for your contributed content')
|
|
403
|
+
.option('--time-range <range>', `Time range: ${ANALYTICS_TIME_RANGES.join(', ')}`, '30d')
|
|
404
|
+
.option('--content-hash <hash>', 'Show per-content detail for a single content hash')
|
|
405
|
+
.action(async (options) => {
|
|
406
|
+
const timeRange = options.timeRange;
|
|
407
|
+
if (!ANALYTICS_TIME_RANGES.includes(timeRange)) {
|
|
408
|
+
outputError(`Invalid --time-range "${timeRange}". Valid values: ${ANALYTICS_TIME_RANGES.join(', ')}`, 'contribute analytics');
|
|
409
|
+
process.exit(1);
|
|
410
|
+
}
|
|
411
|
+
const opts = getGlobalOptions();
|
|
412
|
+
const spinner = opts.json || opts.quiet ? null : ora('Fetching analytics...').start();
|
|
413
|
+
try {
|
|
414
|
+
const data = await postContributeFunction('embed-manage', {
|
|
415
|
+
action: 'get-analytics',
|
|
416
|
+
time_range: timeRange,
|
|
417
|
+
...(options.contentHash ? { content_hash: options.contentHash } : {}),
|
|
418
|
+
});
|
|
419
|
+
spinner?.stop();
|
|
420
|
+
if (getGlobalOptions().json) {
|
|
421
|
+
outputSuccess(data, 'contribute analytics');
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const { summary } = data;
|
|
425
|
+
const totals = [
|
|
426
|
+
['Embeds', String(summary.total_embeds)],
|
|
427
|
+
['Loads', String(summary.total_loads)],
|
|
428
|
+
['Clicks', String(summary.total_clicks)],
|
|
429
|
+
['CTR', summary.click_through_rate],
|
|
430
|
+
];
|
|
431
|
+
if (isDetailAnalytics(data)) {
|
|
432
|
+
logHeader(`Analytics — ${data.summary.content_hash} (last ${timeRange})`);
|
|
433
|
+
log(truncate(data.summary.content, 72));
|
|
434
|
+
log('');
|
|
435
|
+
logTable(['Metric', 'Value'], totals);
|
|
436
|
+
if (data.pages.length > 0) {
|
|
437
|
+
log('');
|
|
438
|
+
logHeader('Top pages');
|
|
439
|
+
logTable(['Page', 'Loads', 'Clicks'], data.pages
|
|
440
|
+
.slice(0, 10)
|
|
441
|
+
.map((p) => [
|
|
442
|
+
truncate(p.pageTitle || p.pageUrl),
|
|
443
|
+
String(p.loads),
|
|
444
|
+
String(p.clicks),
|
|
445
|
+
]));
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
logHeader(`Analytics — all content (last ${timeRange})`);
|
|
450
|
+
logTable(['Metric', 'Value'], totals);
|
|
451
|
+
const topContent = data.performance?.top_performing_content ?? [];
|
|
452
|
+
if (topContent.length > 0) {
|
|
453
|
+
log('');
|
|
454
|
+
logHeader('Top content');
|
|
455
|
+
logTable(['Content', 'Loads', 'Clicks', 'CTR'], topContent
|
|
456
|
+
.slice(0, 10)
|
|
457
|
+
.map((c) => [
|
|
458
|
+
truncate(c.content),
|
|
459
|
+
String(c.loads),
|
|
460
|
+
String(c.clicks),
|
|
461
|
+
c.ctr,
|
|
462
|
+
]));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
spinner?.stop();
|
|
468
|
+
outputError(error instanceof Error ? error.message : 'Failed to fetch analytics', 'contribute analytics');
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
contribute
|
|
473
|
+
.command('payouts')
|
|
474
|
+
.description('List your contributor payouts')
|
|
475
|
+
.action(async () => {
|
|
476
|
+
const opts = getGlobalOptions();
|
|
477
|
+
const spinner = opts.json || opts.quiet ? null : ora('Fetching payouts...').start();
|
|
478
|
+
try {
|
|
479
|
+
const data = await postContributeFunction('contributor-payout', { action: 'list-payouts' });
|
|
480
|
+
spinner?.stop();
|
|
481
|
+
if (getGlobalOptions().json) {
|
|
482
|
+
outputSuccess(data, 'contribute payouts');
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const payouts = data.payouts ?? [];
|
|
486
|
+
if (payouts.length === 0) {
|
|
487
|
+
log('No payouts yet.');
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
logTable(['Created', 'Amount', 'Status'], payouts.map((p) => [
|
|
491
|
+
formatDate(p.createdAt),
|
|
492
|
+
formatAmount(p.payoutAmount, p.payoutCurrency),
|
|
493
|
+
p.payoutStatus,
|
|
494
|
+
]));
|
|
495
|
+
log('');
|
|
496
|
+
log('20% commission, 60-day holding window');
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
spinner?.stop();
|
|
500
|
+
outputError(error instanceof Error ? error.message : 'Failed to fetch payouts', 'contribute payouts');
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
});
|
|
318
504
|
}
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,sBAAsB,CAAA;AAChD,eAAO,MAAM,aAAa,QACgC,CAAA;AAC1D,eAAO,MAAM,YAAY,yBAAyB,CAAA;AAClD,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,aAAa,SAAU,CAAA;AACpC,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAChD,eAAO,MAAM,gBAAgB,YAAY,CAAA;AAGzC,eAAO,MAAM,wBAAwB,YAAY,CAAA;AACjD,eAAO,MAAM,eAAe,YAAY,CAAA;AACxC,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAClD,eAAO,MAAM,YAAY,iBAAiB,CAAA;AAC1C,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,eAAe,4BAA4B,CAAA;AAGxD,eAAO,MAAM,YAAY,QAC+B,CAAA;AAGxD,eAAO,MAAM,eAAe,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,sBAAsB,CAAA;AAChD,eAAO,MAAM,aAAa,QACgC,CAAA;AAC1D,eAAO,MAAM,YAAY,yBAAyB,CAAA;AAClD,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,aAAa,SAAU,CAAA;AACpC,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAChD,eAAO,MAAM,gBAAgB,YAAY,CAAA;AAGzC,eAAO,MAAM,wBAAwB,YAAY,CAAA;AACjD,eAAO,MAAM,eAAe,YAAY,CAAA;AACxC,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAClD,eAAO,MAAM,YAAY,iBAAiB,CAAA;AAC1C,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,eAAe,4BAA4B,CAAA;AAGxD,eAAO,MAAM,YAAY,QAC+B,CAAA;AAGxD,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAQ/C,eAAO,MAAM,cAAc,QACiC,CAAA;AAM5D,eAAO,MAAM,YAAY,QACsD,CAAA;AAC/E,eAAO,MAAM,wBAAwB,QAEa,CAAA"}
|
package/dist/lib/config.js
CHANGED
|
@@ -19,11 +19,12 @@ export const API_BASE_URL = process.env.SKHEMA_API_URL ?? 'https://api.skhema.co
|
|
|
19
19
|
// Environment variable an unattended CI/agent run sets to supply an API key.
|
|
20
20
|
export const API_KEY_ENV_VAR = 'SKHEMA_API_KEY';
|
|
21
21
|
// Public Skhema MCP server endpoint (Streamable HTTP transport). This is the
|
|
22
|
-
// protocol endpoint AI clients connect to —
|
|
23
|
-
//
|
|
24
|
-
// CLI only registers the URL; it
|
|
22
|
+
// protocol endpoint AI clients connect to — mcp.skhema.com IS the MCP server.
|
|
23
|
+
// (The human-facing management UI now lives at app.skhema.com/mcp.) Auth is
|
|
24
|
+
// per-client browser OAuth on first use, so the CLI only registers the URL; it
|
|
25
|
+
// never injects a credential here.
|
|
25
26
|
// Override via env for staging/preview environments.
|
|
26
|
-
export const MCP_SERVER_URL = process.env.SKHEMA_MCP_URL ?? 'https://mcp
|
|
27
|
+
export const MCP_SERVER_URL = process.env.SKHEMA_MCP_URL ?? 'https://mcp.skhema.com/mcp';
|
|
27
28
|
// Supabase project configuration.
|
|
28
29
|
// Publishable keys are safe to embed in client-side code (they are the new
|
|
29
30
|
// replacement for the legacy anon key and rely on RLS + server-side auth
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Supabase edge functions the contributor commands talk to. */
|
|
2
|
+
export type ContributeEdgeFunction = 'contributor-manage' | 'embed-manage' | 'contributor-payout';
|
|
3
|
+
/**
|
|
4
|
+
* POST a JSON action to a Supabase edge function with the stored OAuth session.
|
|
5
|
+
* Shared by every authenticated `contribute` subcommand so the auth headers,
|
|
6
|
+
* base URL, and error mapping live in exactly one place.
|
|
7
|
+
*
|
|
8
|
+
* Resolves the access token itself: the `contribute` group's requireContributor
|
|
9
|
+
* preAction already guarantees an approved session, so callers never plumb a
|
|
10
|
+
* token through. Throws a clear Error on missing auth or a non-2xx response,
|
|
11
|
+
* which the command wraps with outputError + a non-zero exit.
|
|
12
|
+
*/
|
|
13
|
+
export declare function postContributeFunction<T>(fn: ContributeEdgeFunction, body: Record<string, unknown>): Promise<T>;
|
|
14
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/api.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,MAAM,MAAM,sBAAsB,GAC9B,oBAAoB,GACpB,cAAc,GACd,oBAAoB,CAAA;AAExB;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,EAAE,EAAE,sBAAsB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CA+BZ"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getStoredCredentials } from '../auth/token-store.js';
|
|
2
|
+
import { SUPABASE_PUBLISHABLE_KEY, SUPABASE_URL } from '../config.js';
|
|
3
|
+
/**
|
|
4
|
+
* POST a JSON action to a Supabase edge function with the stored OAuth session.
|
|
5
|
+
* Shared by every authenticated `contribute` subcommand so the auth headers,
|
|
6
|
+
* base URL, and error mapping live in exactly one place.
|
|
7
|
+
*
|
|
8
|
+
* Resolves the access token itself: the `contribute` group's requireContributor
|
|
9
|
+
* preAction already guarantees an approved session, so callers never plumb a
|
|
10
|
+
* token through. Throws a clear Error on missing auth or a non-2xx response,
|
|
11
|
+
* which the command wraps with outputError + a non-zero exit.
|
|
12
|
+
*/
|
|
13
|
+
export async function postContributeFunction(fn, body) {
|
|
14
|
+
const credentials = await getStoredCredentials();
|
|
15
|
+
if (!credentials?.access_token) {
|
|
16
|
+
throw new Error('Authentication required. Run "skhema auth login" first.');
|
|
17
|
+
}
|
|
18
|
+
const response = await fetch(`${SUPABASE_URL}/functions/v1/${fn}`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
Authorization: `Bearer ${credentials.access_token}`,
|
|
23
|
+
apikey: SUPABASE_PUBLISHABLE_KEY,
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify(body),
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
// Supabase edge functions and the gateway return `{ message }`, while some
|
|
29
|
+
// handlers return `{ error }` — accept either before the generic fallback.
|
|
30
|
+
const detail = (await response.json().catch(() => ({})));
|
|
31
|
+
throw new Error(detail.error ||
|
|
32
|
+
detail.message ||
|
|
33
|
+
`Request to ${fn} failed: ${response.status}`);
|
|
34
|
+
}
|
|
35
|
+
return (await response.json());
|
|
36
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GenerateComponentEmbedOptions, GenerateComponentEmbedResult, GenerateEmbedOptions, GenerateEmbedResult } from './types.js';
|
|
2
|
+
export declare const EMBED_CDN_VERSION = "0.1.13";
|
|
2
3
|
export declare function generateEmbed(options: GenerateEmbedOptions): GenerateEmbedResult;
|
|
3
4
|
export declare function generateComponentEmbed(options: GenerateComponentEmbedOptions): GenerateComponentEmbedResult;
|
|
4
5
|
//# sourceMappingURL=embed-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed-generator.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/embed-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,4BAA4B,EAC5B,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"embed-generator.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/embed-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,4BAA4B,EAC5B,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAMnB,eAAO,MAAM,iBAAiB,WAAW,CAAA;AAGzC,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CA8DrB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,6BAA6B,GACrC,4BAA4B,CA0G9B"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { COMPONENT_TYPES, ELEMENT_TYPES, SKHEMA_MAPPING, } from '@skhema/method/vocabulary';
|
|
2
|
-
|
|
2
|
+
// Pin the CDN snippet to a published @skhema/embed version. Unversioned unpkg
|
|
3
|
+
// URLs resolve to "latest", so an unversioned snippet silently changes behaviour
|
|
4
|
+
// on every embed publish — a generated snippet must render the same way forever.
|
|
5
|
+
// Bump this in lockstep with @skhema/embed releases.
|
|
6
|
+
export const EMBED_CDN_VERSION = '0.1.13';
|
|
7
|
+
const CDN_URL = `https://unpkg.com/@skhema/embed@${EMBED_CDN_VERSION}/dist/embed.min.js`;
|
|
3
8
|
export function generateEmbed(options) {
|
|
4
9
|
const { elementType, contributorId, authorName, authorSlug, content, theme, trackAnalytics, sourceUrl, } = options;
|
|
5
10
|
if (!contributorId?.trim()) {
|
|
@@ -88,4 +88,78 @@ export interface PublishComponentShareLinkResult {
|
|
|
88
88
|
shareUrl: string;
|
|
89
89
|
componentId: string;
|
|
90
90
|
}
|
|
91
|
+
/** contributor-manage `check-status` */
|
|
92
|
+
export interface ContributorStatusResponse {
|
|
93
|
+
isContributor: boolean;
|
|
94
|
+
approved: boolean;
|
|
95
|
+
contributorId: string | null;
|
|
96
|
+
}
|
|
97
|
+
/** contributor-manage `get-profile` */
|
|
98
|
+
export interface ContributorProfileResponse {
|
|
99
|
+
contributorId: string;
|
|
100
|
+
displayName: string | null;
|
|
101
|
+
displayNamePreference: 'personal' | 'organization';
|
|
102
|
+
bio: string | null;
|
|
103
|
+
avatarUrl: string | null;
|
|
104
|
+
publicWebsiteUrl: string | null;
|
|
105
|
+
resolvedDisplayName: string;
|
|
106
|
+
userName: string | null;
|
|
107
|
+
organizationName: string | null;
|
|
108
|
+
}
|
|
109
|
+
/** embed-manage `get-analytics` (no content hash — the roll-up view) */
|
|
110
|
+
export interface ContributorAnalyticsResponse {
|
|
111
|
+
summary: {
|
|
112
|
+
total_embeds: number;
|
|
113
|
+
total_loads: number;
|
|
114
|
+
total_clicks: number;
|
|
115
|
+
click_through_rate: string;
|
|
116
|
+
};
|
|
117
|
+
performance: {
|
|
118
|
+
top_performing_content: Array<{
|
|
119
|
+
content: string;
|
|
120
|
+
clicks: number;
|
|
121
|
+
loads: number;
|
|
122
|
+
ctr: string;
|
|
123
|
+
content_hash: string;
|
|
124
|
+
element_type: string;
|
|
125
|
+
}>;
|
|
126
|
+
traffic_sources: Array<{
|
|
127
|
+
domain: string;
|
|
128
|
+
loads: number;
|
|
129
|
+
clicks: number;
|
|
130
|
+
percentage: number;
|
|
131
|
+
}>;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** embed-manage `get-analytics` (with content hash — the per-content detail) */
|
|
135
|
+
export interface DetailAnalyticsResponse {
|
|
136
|
+
summary: {
|
|
137
|
+
total_embeds: number;
|
|
138
|
+
total_loads: number;
|
|
139
|
+
total_clicks: number;
|
|
140
|
+
click_through_rate: string;
|
|
141
|
+
content_hash: string;
|
|
142
|
+
element_type: string;
|
|
143
|
+
content: string;
|
|
144
|
+
};
|
|
145
|
+
pages: Array<{
|
|
146
|
+
pageUrl: string;
|
|
147
|
+
pageTitle: string;
|
|
148
|
+
loads: number;
|
|
149
|
+
clicks: number;
|
|
150
|
+
}>;
|
|
151
|
+
}
|
|
152
|
+
/** contributor-payout `list-payouts` */
|
|
153
|
+
export interface PayoutRecord {
|
|
154
|
+
id: string;
|
|
155
|
+
createdAt: string;
|
|
156
|
+
approvalStatus: string;
|
|
157
|
+
payoutStatus: string;
|
|
158
|
+
payoutCurrency: string | null;
|
|
159
|
+
payoutAmount: number | null;
|
|
160
|
+
notes: string | null;
|
|
161
|
+
}
|
|
162
|
+
export interface PayoutListResponse {
|
|
163
|
+
payouts: PayoutRecord[];
|
|
164
|
+
}
|
|
91
165
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/types.ts"],"names":[],"mappings":"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"}
|