sello 0.1.2 → 0.1.3
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 +18 -0
- package/dist/cli/sello.js +165 -1
- package/docs/sdk-quickstart.md +17 -0
- package/package.json +1 -1
- package/src/cli/sello.ts +165 -1
package/README.md
CHANGED
|
@@ -53,6 +53,7 @@ Sello currently requires Node.js 22.7 or newer.
|
|
|
53
53
|
| Goal | Read |
|
|
54
54
|
|------|------|
|
|
55
55
|
| Add Sello in a few lines | [SDK Quickstart](docs/sdk-quickstart.md) |
|
|
56
|
+
| Emit your first receipt | `npx sello dev`, then `npx sello emit-demo` |
|
|
56
57
|
| Try a wrapped tool locally | `node --run dev`, then `node --run example:tool` |
|
|
57
58
|
| Try an MCP-style tool call | `node --run dev`, then `node --run example:mcp` |
|
|
58
59
|
| Understand the protocol | [SPEC.md](SPEC.md) Quick Start |
|
|
@@ -98,6 +99,23 @@ The example wraps a fake calendar tool, emits a service-signed encrypted receipt
|
|
|
98
99
|
|
|
99
100
|
For an MCP-shaped `tools/call` boundary, run `node --run example:mcp` instead of `node --run example:tool`.
|
|
100
101
|
|
|
102
|
+
To try the published package from a fresh project:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Terminal 1
|
|
106
|
+
npx sello dev
|
|
107
|
+
|
|
108
|
+
# Terminal 2
|
|
109
|
+
npx sello emit-demo
|
|
110
|
+
npx sello actions
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
To see the tiny emitter code:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx sello init-demo
|
|
117
|
+
```
|
|
118
|
+
|
|
101
119
|
## The First 10 Minutes
|
|
102
120
|
|
|
103
121
|
If you are implementing Sello, start with one local loop:
|
package/dist/cli/sello.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { createServer, } from "node:http";
|
|
4
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
|
|
7
7
|
import { generateEd25519KeyPair } from "../cose/sign1.js";
|
|
8
8
|
import { deriveTokenIdentifiers, sha256, toHex } from "../crypto/identifiers.js";
|
|
9
9
|
import { generateHpkeKeyPair } from "../hpke/receipt.js";
|
|
10
10
|
import { MockTransparencyLog } from "../log/mock-log.js";
|
|
11
|
+
import { canonicalJsonBytes } from "../mcp/middleware.js";
|
|
11
12
|
import { verifyReceipts } from "../owner/verify.js";
|
|
12
13
|
import {
|
|
13
14
|
loadSignedRegistry,
|
|
@@ -25,10 +26,12 @@ import {
|
|
|
25
26
|
} from "../sdk/keys.js";
|
|
26
27
|
import {
|
|
27
28
|
deserializeEntry,
|
|
29
|
+
http as httpLog,
|
|
28
30
|
queryHttpLogByTokenRef,
|
|
29
31
|
serializeEntry,
|
|
30
32
|
toCanonicalLogUrl,
|
|
31
33
|
} from "../sdk/logs.js";
|
|
34
|
+
import { createSelloService } from "../sdk/service.js";
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
|
|
@@ -56,6 +59,12 @@ try {
|
|
|
56
59
|
case "dev":
|
|
57
60
|
await devCommand(process.argv.slice(3));
|
|
58
61
|
break;
|
|
62
|
+
case "emit-demo":
|
|
63
|
+
await emitDemoCommand(process.argv.slice(3));
|
|
64
|
+
break;
|
|
65
|
+
case "init-demo":
|
|
66
|
+
initDemoCommand(process.argv.slice(3));
|
|
67
|
+
break;
|
|
59
68
|
case "keys":
|
|
60
69
|
keysCommand(process.argv.slice(3));
|
|
61
70
|
break;
|
|
@@ -156,6 +165,75 @@ async function devCommand(args ) {
|
|
|
156
165
|
});
|
|
157
166
|
}
|
|
158
167
|
|
|
168
|
+
async function emitDemoCommand(args ) {
|
|
169
|
+
const state = loadDevStateOrThrow(
|
|
170
|
+
"missing local Sello dev state. Run `sello dev` first, then run `sello emit-demo` in another terminal from the same directory.",
|
|
171
|
+
);
|
|
172
|
+
const title = readFlag(args, "--title") ?? "Test Sello receipt";
|
|
173
|
+
const receipts = createSelloService({
|
|
174
|
+
service: state.serviceId,
|
|
175
|
+
serviceKey: state.serviceKey,
|
|
176
|
+
tokenIssuer: state.tokenIssuerPublicKey,
|
|
177
|
+
log: httpLog(state.logUrl, { endpoint: state.logEndpoint }),
|
|
178
|
+
submit: { mode: "await" },
|
|
179
|
+
});
|
|
180
|
+
const createEvent = receipts.tool (
|
|
181
|
+
"calendar.create_event",
|
|
182
|
+
async (request) => ({
|
|
183
|
+
id: `evt_${slug(request.title)}`,
|
|
184
|
+
calendarId: request.calendarId,
|
|
185
|
+
title: request.title,
|
|
186
|
+
status: "created",
|
|
187
|
+
createdAt: new Date().toISOString(),
|
|
188
|
+
}),
|
|
189
|
+
{
|
|
190
|
+
canonicalizeInput: (request) => canonicalJsonBytes({
|
|
191
|
+
calendarId: request.calendarId,
|
|
192
|
+
title: request.title,
|
|
193
|
+
start: request.start,
|
|
194
|
+
attendees: request.attendees,
|
|
195
|
+
}),
|
|
196
|
+
},
|
|
197
|
+
);
|
|
198
|
+
const response = await createEvent({
|
|
199
|
+
authorizationToken: state.agentToken,
|
|
200
|
+
calendarId: "demo-calendar",
|
|
201
|
+
title,
|
|
202
|
+
start: "2026-06-05T17:00:00Z",
|
|
203
|
+
attendees: ["ada@example.com", "grace@example.com"],
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
await receipts.flush();
|
|
207
|
+
|
|
208
|
+
console.log("Emitted demo Sello receipt.");
|
|
209
|
+
console.log(JSON.stringify(response, null, 2));
|
|
210
|
+
console.log("");
|
|
211
|
+
console.log("View verified actions with:");
|
|
212
|
+
console.log(" sello actions");
|
|
213
|
+
console.log("");
|
|
214
|
+
console.log("Or open:");
|
|
215
|
+
console.log(` ${actionViewerUrl(state)}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function initDemoCommand(args ) {
|
|
219
|
+
const output = readFlag(args, "--output") ?? "emit-receipt.mjs";
|
|
220
|
+
const force = args.includes("--force");
|
|
221
|
+
|
|
222
|
+
if (existsSync(output) && !force) {
|
|
223
|
+
throw new TypeError(`${output} already exists. Pass --force to overwrite it.`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
writeFileSync(output, demoEmitterSource(), { mode: 0o644 });
|
|
227
|
+
|
|
228
|
+
console.log(`Created ${output}`);
|
|
229
|
+
console.log("");
|
|
230
|
+
console.log("Run:");
|
|
231
|
+
console.log(" npm install sello");
|
|
232
|
+
console.log(" npx sello dev");
|
|
233
|
+
console.log(` node ${output}`);
|
|
234
|
+
console.log(" npx sello actions");
|
|
235
|
+
}
|
|
236
|
+
|
|
159
237
|
function keysCommand(args ) {
|
|
160
238
|
const subcommand = args[0] ?? "service";
|
|
161
239
|
if (subcommand !== "service") {
|
|
@@ -338,6 +416,14 @@ function loadDevStateIfPresent() {
|
|
|
338
416
|
}
|
|
339
417
|
}
|
|
340
418
|
|
|
419
|
+
function loadDevStateOrThrow(message ) {
|
|
420
|
+
const state = loadDevStateIfPresent();
|
|
421
|
+
if (!state) {
|
|
422
|
+
throw new TypeError(message);
|
|
423
|
+
}
|
|
424
|
+
return state;
|
|
425
|
+
}
|
|
426
|
+
|
|
341
427
|
function devStatePath() {
|
|
342
428
|
return join(process.cwd(), ".sello", "dev.json");
|
|
343
429
|
}
|
|
@@ -477,6 +563,8 @@ function isRecord(value ) {
|
|
|
477
563
|
function printHelp() {
|
|
478
564
|
console.log(`Usage:
|
|
479
565
|
sello dev [--port 8787] [--service service-id] [--dry-run]
|
|
566
|
+
sello emit-demo [--title title]
|
|
567
|
+
sello init-demo [--output emit-receipt.mjs] [--force]
|
|
480
568
|
sello actions [--token agent-token]
|
|
481
569
|
sello keys service
|
|
482
570
|
sello inspect-env
|
|
@@ -513,3 +601,79 @@ function enforceNodeVersion() {
|
|
|
513
601
|
);
|
|
514
602
|
}
|
|
515
603
|
}
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
function actionViewerUrl(state ) {
|
|
622
|
+
const endpoint = new URL(state.logEndpoint);
|
|
623
|
+
return `${endpoint.origin}/actions`;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function slug(value ) {
|
|
627
|
+
return value
|
|
628
|
+
.toLowerCase()
|
|
629
|
+
.replace(/[^a-z0-9]+/g, "_")
|
|
630
|
+
.replace(/^_+|_+$/g, "")
|
|
631
|
+
.slice(0, 40);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function demoEmitterSource() {
|
|
635
|
+
return `import { readFileSync } from "node:fs";
|
|
636
|
+
import { canonicalJsonBytes, sello } from "sello";
|
|
637
|
+
|
|
638
|
+
const state = JSON.parse(readFileSync(".sello/dev.json", "utf8"));
|
|
639
|
+
|
|
640
|
+
const receipts = sello.service({
|
|
641
|
+
service: state.serviceId,
|
|
642
|
+
serviceKey: state.serviceKey,
|
|
643
|
+
tokenIssuer: state.tokenIssuerPublicKey,
|
|
644
|
+
log: sello.logs.http(state.logUrl, { endpoint: state.logEndpoint }),
|
|
645
|
+
submit: { mode: "await" },
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
const createEvent = receipts.tool(
|
|
649
|
+
"calendar.create_event",
|
|
650
|
+
async (request) => ({
|
|
651
|
+
id: "evt_test_sello_receipt",
|
|
652
|
+
calendarId: request.calendarId,
|
|
653
|
+
title: request.title,
|
|
654
|
+
status: "created",
|
|
655
|
+
createdAt: new Date().toISOString(),
|
|
656
|
+
}),
|
|
657
|
+
{
|
|
658
|
+
canonicalizeInput: (request) =>
|
|
659
|
+
canonicalJsonBytes({
|
|
660
|
+
calendarId: request.calendarId,
|
|
661
|
+
title: request.title,
|
|
662
|
+
start: request.start,
|
|
663
|
+
attendees: request.attendees,
|
|
664
|
+
}),
|
|
665
|
+
},
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
const result = await createEvent({
|
|
669
|
+
authorizationToken: state.agentToken,
|
|
670
|
+
calendarId: "demo-calendar",
|
|
671
|
+
title: "Test Sello receipt",
|
|
672
|
+
start: "2026-06-05T17:00:00Z",
|
|
673
|
+
attendees: ["ada@example.com", "grace@example.com"],
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
await receipts.flush();
|
|
677
|
+
console.log(result);
|
|
678
|
+
`;
|
|
679
|
+
}
|
package/docs/sdk-quickstart.md
CHANGED
|
@@ -18,6 +18,23 @@ The service process emits receipts. It does not need the owner private key.
|
|
|
18
18
|
|
|
19
19
|
## Local Development
|
|
20
20
|
|
|
21
|
+
From a new project, the shortest loop is:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Terminal 1
|
|
25
|
+
npx sello dev
|
|
26
|
+
|
|
27
|
+
# Terminal 2
|
|
28
|
+
npx sello emit-demo
|
|
29
|
+
npx sello actions
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
To write the tiny emitter file into your project:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx sello init-demo
|
|
36
|
+
```
|
|
37
|
+
|
|
21
38
|
Inside this repo, start the local log and action viewer:
|
|
22
39
|
|
|
23
40
|
```bash
|
package/package.json
CHANGED
package/src/cli/sello.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --experimental-strip-types
|
|
2
2
|
|
|
3
3
|
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
|
|
4
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
|
|
7
7
|
import { generateEd25519KeyPair } from "../cose/sign1.ts";
|
|
@@ -9,6 +9,7 @@ import { deriveTokenIdentifiers, sha256, toHex } from "../crypto/identifiers.ts"
|
|
|
9
9
|
import { generateHpkeKeyPair } from "../hpke/receipt.ts";
|
|
10
10
|
import { type CanonicalLogUrl } from "../log/canonical-url.ts";
|
|
11
11
|
import { MockTransparencyLog } from "../log/mock-log.ts";
|
|
12
|
+
import { canonicalJsonBytes } from "../mcp/middleware.ts";
|
|
12
13
|
import { verifyReceipts } from "../owner/verify.ts";
|
|
13
14
|
import {
|
|
14
15
|
loadSignedRegistry,
|
|
@@ -26,10 +27,12 @@ import {
|
|
|
26
27
|
} from "../sdk/keys.ts";
|
|
27
28
|
import {
|
|
28
29
|
deserializeEntry,
|
|
30
|
+
http as httpLog,
|
|
29
31
|
queryHttpLogByTokenRef,
|
|
30
32
|
serializeEntry,
|
|
31
33
|
toCanonicalLogUrl,
|
|
32
34
|
} from "../sdk/logs.ts";
|
|
35
|
+
import { createSelloService } from "../sdk/service.ts";
|
|
33
36
|
|
|
34
37
|
type DevState = {
|
|
35
38
|
serviceId: string;
|
|
@@ -57,6 +60,12 @@ try {
|
|
|
57
60
|
case "dev":
|
|
58
61
|
await devCommand(process.argv.slice(3));
|
|
59
62
|
break;
|
|
63
|
+
case "emit-demo":
|
|
64
|
+
await emitDemoCommand(process.argv.slice(3));
|
|
65
|
+
break;
|
|
66
|
+
case "init-demo":
|
|
67
|
+
initDemoCommand(process.argv.slice(3));
|
|
68
|
+
break;
|
|
60
69
|
case "keys":
|
|
61
70
|
keysCommand(process.argv.slice(3));
|
|
62
71
|
break;
|
|
@@ -157,6 +166,75 @@ async function devCommand(args: string[]): Promise<void> {
|
|
|
157
166
|
});
|
|
158
167
|
}
|
|
159
168
|
|
|
169
|
+
async function emitDemoCommand(args: string[]): Promise<void> {
|
|
170
|
+
const state = loadDevStateOrThrow(
|
|
171
|
+
"missing local Sello dev state. Run `sello dev` first, then run `sello emit-demo` in another terminal from the same directory.",
|
|
172
|
+
);
|
|
173
|
+
const title = readFlag(args, "--title") ?? "Test Sello receipt";
|
|
174
|
+
const receipts = createSelloService({
|
|
175
|
+
service: state.serviceId,
|
|
176
|
+
serviceKey: state.serviceKey,
|
|
177
|
+
tokenIssuer: state.tokenIssuerPublicKey,
|
|
178
|
+
log: httpLog(state.logUrl, { endpoint: state.logEndpoint }),
|
|
179
|
+
submit: { mode: "await" },
|
|
180
|
+
});
|
|
181
|
+
const createEvent = receipts.tool<DemoEventRequest, DemoEventResponse>(
|
|
182
|
+
"calendar.create_event",
|
|
183
|
+
async (request) => ({
|
|
184
|
+
id: `evt_${slug(request.title)}`,
|
|
185
|
+
calendarId: request.calendarId,
|
|
186
|
+
title: request.title,
|
|
187
|
+
status: "created",
|
|
188
|
+
createdAt: new Date().toISOString(),
|
|
189
|
+
}),
|
|
190
|
+
{
|
|
191
|
+
canonicalizeInput: (request) => canonicalJsonBytes({
|
|
192
|
+
calendarId: request.calendarId,
|
|
193
|
+
title: request.title,
|
|
194
|
+
start: request.start,
|
|
195
|
+
attendees: request.attendees,
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
const response = await createEvent({
|
|
200
|
+
authorizationToken: state.agentToken,
|
|
201
|
+
calendarId: "demo-calendar",
|
|
202
|
+
title,
|
|
203
|
+
start: "2026-06-05T17:00:00Z",
|
|
204
|
+
attendees: ["ada@example.com", "grace@example.com"],
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
await receipts.flush();
|
|
208
|
+
|
|
209
|
+
console.log("Emitted demo Sello receipt.");
|
|
210
|
+
console.log(JSON.stringify(response, null, 2));
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log("View verified actions with:");
|
|
213
|
+
console.log(" sello actions");
|
|
214
|
+
console.log("");
|
|
215
|
+
console.log("Or open:");
|
|
216
|
+
console.log(` ${actionViewerUrl(state)}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function initDemoCommand(args: string[]): void {
|
|
220
|
+
const output = readFlag(args, "--output") ?? "emit-receipt.mjs";
|
|
221
|
+
const force = args.includes("--force");
|
|
222
|
+
|
|
223
|
+
if (existsSync(output) && !force) {
|
|
224
|
+
throw new TypeError(`${output} already exists. Pass --force to overwrite it.`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
writeFileSync(output, demoEmitterSource(), { mode: 0o644 });
|
|
228
|
+
|
|
229
|
+
console.log(`Created ${output}`);
|
|
230
|
+
console.log("");
|
|
231
|
+
console.log("Run:");
|
|
232
|
+
console.log(" npm install sello");
|
|
233
|
+
console.log(" npx sello dev");
|
|
234
|
+
console.log(` node ${output}`);
|
|
235
|
+
console.log(" npx sello actions");
|
|
236
|
+
}
|
|
237
|
+
|
|
160
238
|
function keysCommand(args: string[]): void {
|
|
161
239
|
const subcommand = args[0] ?? "service";
|
|
162
240
|
if (subcommand !== "service") {
|
|
@@ -339,6 +417,14 @@ function loadDevStateIfPresent(): DevState | undefined {
|
|
|
339
417
|
}
|
|
340
418
|
}
|
|
341
419
|
|
|
420
|
+
function loadDevStateOrThrow(message: string): DevState {
|
|
421
|
+
const state = loadDevStateIfPresent();
|
|
422
|
+
if (!state) {
|
|
423
|
+
throw new TypeError(message);
|
|
424
|
+
}
|
|
425
|
+
return state;
|
|
426
|
+
}
|
|
427
|
+
|
|
342
428
|
function devStatePath(): string {
|
|
343
429
|
return join(process.cwd(), ".sello", "dev.json");
|
|
344
430
|
}
|
|
@@ -478,6 +564,8 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
478
564
|
function printHelp(): void {
|
|
479
565
|
console.log(`Usage:
|
|
480
566
|
sello dev [--port 8787] [--service service-id] [--dry-run]
|
|
567
|
+
sello emit-demo [--title title]
|
|
568
|
+
sello init-demo [--output emit-receipt.mjs] [--force]
|
|
481
569
|
sello actions [--token agent-token]
|
|
482
570
|
sello keys service
|
|
483
571
|
sello inspect-env
|
|
@@ -514,3 +602,79 @@ function enforceNodeVersion(): void {
|
|
|
514
602
|
);
|
|
515
603
|
}
|
|
516
604
|
}
|
|
605
|
+
|
|
606
|
+
type DemoEventRequest = {
|
|
607
|
+
authorizationToken: string;
|
|
608
|
+
calendarId: string;
|
|
609
|
+
title: string;
|
|
610
|
+
start: string;
|
|
611
|
+
attendees: string[];
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
type DemoEventResponse = {
|
|
615
|
+
id: string;
|
|
616
|
+
calendarId: string;
|
|
617
|
+
title: string;
|
|
618
|
+
status: "created";
|
|
619
|
+
createdAt: string;
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
function actionViewerUrl(state: DevState): string {
|
|
623
|
+
const endpoint = new URL(state.logEndpoint);
|
|
624
|
+
return `${endpoint.origin}/actions`;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function slug(value: string): string {
|
|
628
|
+
return value
|
|
629
|
+
.toLowerCase()
|
|
630
|
+
.replace(/[^a-z0-9]+/g, "_")
|
|
631
|
+
.replace(/^_+|_+$/g, "")
|
|
632
|
+
.slice(0, 40);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function demoEmitterSource(): string {
|
|
636
|
+
return `import { readFileSync } from "node:fs";
|
|
637
|
+
import { canonicalJsonBytes, sello } from "sello";
|
|
638
|
+
|
|
639
|
+
const state = JSON.parse(readFileSync(".sello/dev.json", "utf8"));
|
|
640
|
+
|
|
641
|
+
const receipts = sello.service({
|
|
642
|
+
service: state.serviceId,
|
|
643
|
+
serviceKey: state.serviceKey,
|
|
644
|
+
tokenIssuer: state.tokenIssuerPublicKey,
|
|
645
|
+
log: sello.logs.http(state.logUrl, { endpoint: state.logEndpoint }),
|
|
646
|
+
submit: { mode: "await" },
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
const createEvent = receipts.tool(
|
|
650
|
+
"calendar.create_event",
|
|
651
|
+
async (request) => ({
|
|
652
|
+
id: "evt_test_sello_receipt",
|
|
653
|
+
calendarId: request.calendarId,
|
|
654
|
+
title: request.title,
|
|
655
|
+
status: "created",
|
|
656
|
+
createdAt: new Date().toISOString(),
|
|
657
|
+
}),
|
|
658
|
+
{
|
|
659
|
+
canonicalizeInput: (request) =>
|
|
660
|
+
canonicalJsonBytes({
|
|
661
|
+
calendarId: request.calendarId,
|
|
662
|
+
title: request.title,
|
|
663
|
+
start: request.start,
|
|
664
|
+
attendees: request.attendees,
|
|
665
|
+
}),
|
|
666
|
+
},
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
const result = await createEvent({
|
|
670
|
+
authorizationToken: state.agentToken,
|
|
671
|
+
calendarId: "demo-calendar",
|
|
672
|
+
title: "Test Sello receipt",
|
|
673
|
+
start: "2026-06-05T17:00:00Z",
|
|
674
|
+
attendees: ["ada@example.com", "grace@example.com"],
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
await receipts.flush();
|
|
678
|
+
console.log(result);
|
|
679
|
+
`;
|
|
680
|
+
}
|