@rubytech/create-maxy-code 0.1.451 → 0.1.453
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/dist/__tests__/preserve-house-cloudflare.test.js +81 -2
- package/dist/index.js +10 -1
- package/dist/preserve-house-cloudflare.js +49 -2
- package/package.json +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +24 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/house-scoped-token.test.d.ts +2 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/house-scoped-token.test.d.ts.map +1 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/house-scoped-token.test.js +48 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/house-scoped-token.test.js.map +1 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/remediate.test.js +6 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/remediate.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/bin/remediate-run.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/bin/remediate-run.js +14 -4
- package/payload/platform/lib/storage-broker/dist/bin/remediate-run.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +1 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +18 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.d.ts +9 -0
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.d.ts.map +1 -0
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js +60 -0
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js.map +1 -0
- package/payload/platform/lib/storage-broker/dist/index.d.ts +1 -0
- package/payload/platform/lib/storage-broker/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/index.js +1 -0
- package/payload/platform/lib/storage-broker/dist/index.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/remediate.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/remediate.js +14 -1
- package/payload/platform/lib/storage-broker/dist/remediate.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +28 -1
- package/payload/platform/lib/storage-broker/src/__tests__/house-scoped-token.test.ts +48 -0
- package/payload/platform/lib/storage-broker/src/__tests__/remediate.test.ts +8 -0
- package/payload/platform/lib/storage-broker/src/bin/remediate-run.ts +17 -5
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +22 -0
- package/payload/platform/lib/storage-broker/src/house-scoped-token.ts +72 -0
- package/payload/platform/lib/storage-broker/src/index.ts +1 -0
- package/payload/platform/lib/storage-broker/src/remediate.ts +14 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/hooks/__tests__/quote-render-gate.test.sh +107 -0
- package/payload/platform/plugins/admin/hooks/quote-render-gate.sh +74 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -4
- package/payload/platform/plugins/cloudflare/bin/__tests__/cf-token.test.sh +25 -1
- package/payload/platform/plugins/cloudflare/bin/cf-token.sh +9 -1
- package/payload/platform/plugins/cloudflare/references/api.md +3 -1
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +1 -1
- package/payload/platform/plugins/docs/references/outlook-guide.md +3 -3
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +3 -3
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.js +131 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.js +55 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.js +120 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.js +66 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.js +48 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.d.ts +31 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.js +47 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.d.ts +11 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.js +31 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +13 -9
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +19 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +14 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.js +111 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +16 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +37 -7
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts +12 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +16 -12
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -1
- package/payload/platform/plugins/outlook/references/auth.md +2 -0
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +20 -9
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +7 -7
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.js +36 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/house-scoped-token.d.ts +9 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/house-scoped-token.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/house-scoped-token.js +51 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/house-scoped-token.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +16 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +16 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/scripts/lib/provision-account-dir.sh +6 -0
- package/payload/platform/scripts/smoke-boot-services.sh +1 -0
- package/payload/platform/scripts/voice-mirror-audit.sh +70 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +7 -1
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +15 -0
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +38 -3
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +21 -10
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +20 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/plugin-enum.d.ts +34 -0
- package/payload/platform/services/claude-session-manager/dist/plugin-enum.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/plugin-enum.js +66 -0
- package/payload/platform/services/claude-session-manager/dist/plugin-enum.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/server/{chunk-TTKYHVA7.js → chunk-SDYRKIYY.js} +70 -3
- package/payload/server/server.js +59 -10
- package/payload/server/{src-FBUXV2FV.js → src-554BYJMN.js} +5 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { callGraphPaged } from "../lib/graph-client.js";
|
|
2
2
|
import { log } from "../lib/log.js";
|
|
3
3
|
/**
|
|
4
4
|
* Map a caller-supplied `folder` value to the Graph `/me/mailFolders/{id}`
|
|
@@ -44,22 +44,47 @@ const WELL_KNOWN_ALIASES = {
|
|
|
44
44
|
outbox: "outbox",
|
|
45
45
|
};
|
|
46
46
|
const FIELDS = "id,subject,from,receivedDateTime,bodyPreview,isRead";
|
|
47
|
+
function toGraphDate(input, field) {
|
|
48
|
+
const d = new Date(input);
|
|
49
|
+
if (!Number.isFinite(d.getTime())) {
|
|
50
|
+
throw new Error(`mail-list: ${field} is not a valid date: ${input}`);
|
|
51
|
+
}
|
|
52
|
+
return d.toISOString();
|
|
53
|
+
}
|
|
54
|
+
function buildDateFilter(since, before) {
|
|
55
|
+
const clauses = [];
|
|
56
|
+
if (since)
|
|
57
|
+
clauses.push(`receivedDateTime ge ${toGraphDate(since, "since")}`);
|
|
58
|
+
if (before)
|
|
59
|
+
clauses.push(`receivedDateTime le ${toGraphDate(before, "before")}`);
|
|
60
|
+
return clauses.length > 0 ? clauses.join(" and ") : undefined;
|
|
61
|
+
}
|
|
47
62
|
export async function runMailList(config, args) {
|
|
48
63
|
const top = clampTop(args.top, 25);
|
|
49
64
|
const folderIn = args.folder ?? "Inbox";
|
|
50
65
|
const { token: folderResolved, asRawId } = resolveFolder(folderIn);
|
|
66
|
+
// With a cursor the nextLink already bakes in the window, so since/before are
|
|
67
|
+
// ignored entirely — including their validation. Without a cursor, an
|
|
68
|
+
// unparseable date throws here before any Graph call is made.
|
|
69
|
+
const filter = args.cursor ? undefined : buildDateFilter(args.since, args.before);
|
|
51
70
|
const startMs = Date.now();
|
|
52
71
|
try {
|
|
53
|
-
const
|
|
72
|
+
const page = await callGraphPaged(config, (client) => {
|
|
73
|
+
// A cursor is a full nextLink URL that already encodes
|
|
74
|
+
// folder/filter/order/top/skiptoken — delegate straight to it.
|
|
75
|
+
if (args.cursor)
|
|
76
|
+
return client.api(args.cursor);
|
|
54
77
|
const path = `/me/mailFolders/${encodeURIComponent(folderResolved)}/messages`;
|
|
55
|
-
|
|
78
|
+
const base = client
|
|
56
79
|
.api(path)
|
|
57
80
|
.top(top)
|
|
58
81
|
.orderby("receivedDateTime DESC")
|
|
59
|
-
.select(FIELDS)
|
|
60
|
-
|
|
82
|
+
.select(FIELDS);
|
|
83
|
+
// Date-only filter orders by the same property, so filter+orderby is
|
|
84
|
+
// accepted by Graph (unlike a from/toRecipients filter).
|
|
85
|
+
return filter ? base.filter(filter) : base;
|
|
61
86
|
}, { tool: "mail-list" });
|
|
62
|
-
const items =
|
|
87
|
+
const items = page.value.map(shapeMessage);
|
|
63
88
|
log({
|
|
64
89
|
event: "mail-list",
|
|
65
90
|
op: "resolve",
|
|
@@ -67,10 +92,13 @@ export async function runMailList(config, args) {
|
|
|
67
92
|
folderIn,
|
|
68
93
|
folderResolved,
|
|
69
94
|
asRawId,
|
|
95
|
+
since: args.since ?? null,
|
|
96
|
+
before: args.before ?? null,
|
|
70
97
|
count: items.length,
|
|
98
|
+
nextCursor: page.nextLink ? "present" : "none",
|
|
71
99
|
elapsedMs: Date.now() - startMs,
|
|
72
100
|
});
|
|
73
|
-
return items;
|
|
101
|
+
return { items, nextCursor: page.nextLink };
|
|
74
102
|
}
|
|
75
103
|
catch (err) {
|
|
76
104
|
// callGraph already logged the graph-error line (status/code, e.g. the 400
|
|
@@ -83,6 +111,8 @@ export async function runMailList(config, args) {
|
|
|
83
111
|
folderIn,
|
|
84
112
|
folderResolved,
|
|
85
113
|
asRawId,
|
|
114
|
+
since: args.since ?? null,
|
|
115
|
+
before: args.before ?? null,
|
|
86
116
|
error: err.message,
|
|
87
117
|
elapsedMs: Date.now() - startMs,
|
|
88
118
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-list.js","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mail-list.js","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,17 @@ import type { MailListItem } from "./mail-list.js";
|
|
|
3
3
|
export interface MailSearchArgs {
|
|
4
4
|
query: string;
|
|
5
5
|
top?: number;
|
|
6
|
+
/**
|
|
7
|
+
* Opaque continuation from a prior call's `nextCursor` (an `@odata.nextLink`
|
|
8
|
+
* URL). When set, `query` is ignored — the nextLink re-issues the original
|
|
9
|
+
* search with its `$skiptoken`.
|
|
10
|
+
*/
|
|
11
|
+
cursor?: string;
|
|
6
12
|
}
|
|
7
|
-
export
|
|
13
|
+
export interface MailSearchResult {
|
|
14
|
+
items: MailListItem[];
|
|
15
|
+
/** Opaque cursor for the next page; null when exhausted. */
|
|
16
|
+
nextCursor: string | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function runMailSearch(config: GraphClientConfig, args: MailSearchArgs): Promise<MailSearchResult>;
|
|
8
19
|
//# sourceMappingURL=mail-search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-search.d.ts","sourceRoot":"","sources":["../../src/tools/mail-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-search.d.ts","sourceRoot":"","sources":["../../src/tools/mail-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAID,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,gBAAgB,CAAC,CA8C3B"}
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { callGraphPaged } from "../lib/graph-client.js";
|
|
2
2
|
import { log, trunc } from "../lib/log.js";
|
|
3
3
|
const FIELDS = "id,subject,from,receivedDateTime,bodyPreview,isRead";
|
|
4
4
|
export async function runMailSearch(config, args) {
|
|
5
5
|
const top = clampTop(args.top, 25);
|
|
6
6
|
const query = args.query.trim();
|
|
7
|
-
if (!query) {
|
|
7
|
+
if (!args.cursor && !query) {
|
|
8
8
|
throw new Error("mail-search: query is required and must be non-empty.");
|
|
9
9
|
}
|
|
10
10
|
const startMs = Date.now();
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const page = await callGraphPaged(config, (client) => {
|
|
12
|
+
if (args.cursor) {
|
|
13
|
+
// The nextLink already carries $search + $skiptoken; ConsistencyLevel is
|
|
14
|
+
// a header (not in the URL) and must be re-applied for $search continuation.
|
|
15
|
+
return client.api(args.cursor).header("ConsistencyLevel", "eventual");
|
|
16
|
+
}
|
|
17
|
+
// Graph requires the $search value to be enclosed in quotes, and the
|
|
18
|
+
// ConsistencyLevel header for $search.
|
|
19
|
+
return client
|
|
14
20
|
.api("/me/messages")
|
|
15
21
|
.search(`"${query.replace(/"/g, '\\"')}"`)
|
|
16
22
|
.top(top)
|
|
17
23
|
.select(FIELDS)
|
|
18
|
-
|
|
19
|
-
// accept .header; newer shapes expose it via .request().
|
|
20
|
-
.header("ConsistencyLevel", "eventual")
|
|
21
|
-
.get());
|
|
24
|
+
.header("ConsistencyLevel", "eventual");
|
|
22
25
|
}, { tool: "mail-search" });
|
|
23
|
-
const items =
|
|
26
|
+
const items = page.value.map((msg) => ({
|
|
24
27
|
id: msg.id,
|
|
25
28
|
subject: msg.subject ?? null,
|
|
26
29
|
from: msg.from?.emailAddress?.address ?? null,
|
|
@@ -31,11 +34,12 @@ export async function runMailSearch(config, args) {
|
|
|
31
34
|
log({
|
|
32
35
|
event: "mail-search",
|
|
33
36
|
account: config.accountId,
|
|
34
|
-
query: trunc(query, 32),
|
|
37
|
+
query: args.cursor ? "(cursor)" : trunc(query, 32),
|
|
35
38
|
count: items.length,
|
|
39
|
+
nextCursor: page.nextLink ? "present" : "none",
|
|
36
40
|
elapsedMs: Date.now() - startMs,
|
|
37
41
|
});
|
|
38
|
-
return items;
|
|
42
|
+
return { items, nextCursor: page.nextLink };
|
|
39
43
|
}
|
|
40
44
|
function clampTop(input, fallback) {
|
|
41
45
|
if (typeof input !== "number" || !Number.isFinite(input))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-search.js","sourceRoot":"","sources":["../../src/tools/mail-search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mail-search.js","sourceRoot":"","sources":["../../src/tools/mail-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -81,6 +81,8 @@ operator plugin
|
|
|
81
81
|
|
|
82
82
|
`poll` maps Microsoft's polling errors: `authorization_pending` → `pending` (wait `intervalSec`, poll again), `slow_down` → `pending` with a bumped interval, `expired_token` → `expired`, `access_denied` → `denied`.
|
|
83
83
|
|
|
84
|
+
**Server-driven completion.** The poll does not depend on an agent calling it. The always-running `platform/ui` server spawns a self-contained completion dispatcher (`mcp/dist/scripts/complete-registration.js`) on a 30 s interval; it enumerates every account holding a live pending device code and loops `runAccountRegisterPoll` to a terminal outcome, so a mailbox connects on its own once the operator consents. The dispatcher is PID-locked against overlap, inherits `OUTLOOK_CLIENT_ID` / `OUTLOOK_TENANT_ID` from the session-manager env, and is a no-op when the client id is unconfigured. `outlook-account-register-poll` remains the manual path and the fallback if the dispatcher is down. Observability: one `devicecode-autopoll account=<id> status=<status>` line per poll cycle, plus an independent server-side `devicecode-stranded account=<id> ageSec=<N>` audit that flags any `pending-devicecode.enc` older than the maximum code lifetime (the standing signal that the dispatcher is not running).
|
|
85
|
+
|
|
84
86
|
### Re-registering an account that already consented
|
|
85
87
|
|
|
86
88
|
First-time registration completes cleanly. Re-registering a mailbox whose Microsoft account has **already granted this app access** on a prior registration does not: after the operator enters the user code, Microsoft's consent step redirects the browser to `http://localhost/?error=invalid_request&error_description=...response_type...`, a "site can't be reached" dead-end, and consent never finishes. Observed for personal accounts (outlook.com, hotmail.com, live.com), whose completion runs through the consumer stack (`login.live.com` `msaidpvalidate` → `post.srf`).
|
|
@@ -8,6 +8,10 @@ Microsoft Graph endpoints used by each tool, with the response shape and the fie
|
|
|
8
8
|
|
|
9
9
|
**Endpoint (other folder):** `GET /me/mailFolders/{well-known-token-or-folderId}/messages?...`
|
|
10
10
|
|
|
11
|
+
**Date window:** `since`/`before` (ISO date-times) add `$filter=receivedDateTime ge {since} and receivedDateTime le {before}`. The filter orders by the same `receivedDateTime` property, so `$filter`+`$orderby` is accepted here — a `$filter` on `from`/`toRecipients` combined with this `$orderby` is *not* (Graph: "the restriction or sort order is too complex"), which is why sender/subject filtering lives on `outlook-mail-search` (KQL), not here.
|
|
12
|
+
|
|
13
|
+
**Pagination:** the response's `@odata.nextLink` (a URL carrying a `$skiptoken`) is returned to the caller as `nextCursor`. Passing it back as `cursor` re-issues that exact URL (`client.api(cursor)`), so folder/filter/order/top/skiptoken are preserved and every other arg is ignored. `nextCursor` is `null` when the page is the last. The 250 `$top` is a per-page size, not a reach ceiling — page with the cursor or narrow with the date window to reach older mail.
|
|
14
|
+
|
|
11
15
|
The `folder` arg is normalized before the path is built. Graph's `{id}` segment accepts only a well-known token (single word, no spaces) or a real folder id — a display name like "Sent Items" is rejected with "Id is malformed". The tool maps the full well-known set plus common aliases, case- and space-insensitively, to the Graph token:
|
|
12
16
|
|
|
13
17
|
| Input (any case/spacing) | Graph token |
|
|
@@ -24,14 +28,17 @@ Any value not in this table is treated as a raw folder id and passed through unc
|
|
|
24
28
|
|
|
25
29
|
**Returned shape:**
|
|
26
30
|
```typescript
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
{
|
|
32
|
+
items: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
subject: string | null;
|
|
35
|
+
from: string | null; // emailAddress.address
|
|
36
|
+
receivedDateTime: string; // ISO 8601
|
|
37
|
+
bodyPreview: string; // Microsoft's short preview (~255 chars); the code's .slice(0,1024) never bites. Full body: outlook-mail-fetch-body
|
|
38
|
+
isRead: boolean;
|
|
39
|
+
}>;
|
|
40
|
+
nextCursor: string | null; // @odata.nextLink for the next older page; null when exhausted
|
|
41
|
+
}
|
|
35
42
|
```
|
|
36
43
|
|
|
37
44
|
## outlook-mail-search
|
|
@@ -40,7 +47,11 @@ Array<{
|
|
|
40
47
|
|
|
41
48
|
**Required header:** `ConsistencyLevel: eventual` (Graph requirement for `$search`).
|
|
42
49
|
|
|
43
|
-
**
|
|
50
|
+
**Query filters (KQL):** put sender/subject/recipient/date in the `query` — `from:addr`, `to:addr`, `subject:text`, `received>=2024-01-01`, or free text. Graph forbids combining `$search` with a `$filter`/`$orderby`, so a strict `receivedDateTime` window is on `outlook-mail-list`; date-narrowing here uses the `received:` KQL term.
|
|
51
|
+
|
|
52
|
+
**Pagination:** same as `outlook-mail-list` — the `@odata.nextLink` is returned as `nextCursor`; pass it back as `cursor` and it re-issues via `client.api(cursor)` with the `ConsistencyLevel: eventual` header re-applied (the header is not part of the URL). `cursor` supersedes `query`.
|
|
53
|
+
|
|
54
|
+
**Returned shape:** identical to `outlook-mail-list` (`{ items, nextCursor }`).
|
|
44
55
|
|
|
45
56
|
## outlook-mail-fetch-body
|
|
46
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: outlook
|
|
3
|
-
description: "Microsoft 365 / Outlook.com via Microsoft Graph. Mail is read (list, search, full-body), reply, delete, and compose (draft, draft-edit, send); contacts are read-only; the calendar is read plus control. Use when the user asks about their Outlook mail, calendar, or contacts, wants to read a full message, reply, delete, send or draft a message, or asks to book, move, cancel, or accept a calendar event. First-time use requires outlook-account-register plus outlook-account-register-poll; subsequent use is transparent. Tools: outlook-mail-list / outlook-mail-search (inbox triage, ~255-char preview), outlook-mail-fetch-body (full body of one message), outlook-mail-reply (in-thread reply with attachments), outlook-mail-delete (move to Deleted Items), outlook-mail-otp-extract (poll for a one-time code), outlook-mail-send / outlook-draft / outlook-draft-edit / outlook-draft-send (compose, edit, send), outlook-calendar-list / outlook-calendar-event (read calendar), outlook-calendar-create / outlook-calendar-update / outlook-calendar-cancel / outlook-calendar-respond / outlook-calendar-freebusy (control calendar), outlook-contacts-list (contacts), outlook-mailbox-info (health), outlook-account-register / outlook-account-register-poll (device-code register)."
|
|
3
|
+
description: "Microsoft 365 / Outlook.com via Microsoft Graph. Mail is read (list, search, full-body), reply, delete, and compose (draft, draft-edit, send); contacts are read-only; the calendar is read plus control. Use when the user asks about their Outlook mail, calendar, or contacts, wants to read a full message, reply, delete, send or draft a message, or asks to book, move, cancel, or accept a calendar event. First-time use requires outlook-account-register plus outlook-account-register-poll; subsequent use is transparent. Tools: outlook-mail-list / outlook-mail-search (inbox triage, ~255-char preview, date window + nextCursor paging), outlook-mail-fetch-body (full body of one message), outlook-mail-reply (in-thread reply with attachments), outlook-mail-delete (move to Deleted Items), outlook-mail-otp-extract (poll for a one-time code), outlook-mail-send / outlook-draft / outlook-draft-edit / outlook-draft-send (compose, edit, send), outlook-calendar-list / outlook-calendar-event (read calendar), outlook-calendar-create / outlook-calendar-update / outlook-calendar-cancel / outlook-calendar-respond / outlook-calendar-freebusy (control calendar), outlook-contacts-list (contacts), outlook-mailbox-info (health), outlook-account-register / outlook-account-register-poll (device-code register)."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Outlook (Microsoft Graph)
|
|
@@ -31,11 +31,11 @@ Connect a mailbox via the device-code flow. The operator never needs the box's b
|
|
|
31
31
|
|
|
32
32
|
1. Call **`outlook-account-register`**. It returns immediately with `{ status: "pending", userCode, verificationUri, verificationUriComplete, expiresInSec, intervalSec }`. Relay the `userCode` and `verificationUri` to the operator in your reply so the sign-in can begin.
|
|
33
33
|
2. The operator opens `verificationUri` (`microsoft.com/devicelogin`) on any device (their phone or laptop), enters the `userCode`, signs in with the Microsoft account they want to connect, and consents to the requested scopes (`offline_access`, `User.Read`, `Mail.ReadWrite`, `Mail.Send`, `Calendars.ReadWrite`, `Contacts.Read`). `Mail.Send` enables sending and `Calendars.ReadWrite` enables calendar control; a mailbox last consented on an older read-only scope set must re-register before send or any calendar write succeeds.
|
|
34
|
-
3. **
|
|
34
|
+
3. **The server completes the sign-in automatically. You do not need to poll.** As soon as the code is issued in step 1, a background dispatcher on the server begins polling Microsoft on the code's own cadence and harvests the token the moment the operator finishes consenting, usually within about half a minute. The flow is poll-driven (Microsoft's confirmation page authenticates the code at Microsoft and pushes nothing back to this plugin), and the server is what polls it, so a mailbox connects on its own with no further action from you. Once the operator says they have entered the code and consented, confirm the mailbox is addressable with `outlook-mailbox-info` or `outlook-mailbox-list` (a `status:ok` entry). `outlook-account-register-poll` stays available to force an immediate check, and is the fallback if the server dispatcher is not running: `{ status: "pending" }` means still waiting, `{ status: "registered", graphUserId, scopes, tokenExpSec }` is the completion signal, `{ status: "expired" }` means the code lapsed so restart at step 1, `{ status: "denied" }` means the operator declined.
|
|
35
35
|
|
|
36
|
-
**An operator "done" means
|
|
36
|
+
**An operator "done" means confirm, not poll.** A message like "done", "he confirmed", or "she signed in" means the server has harvested the token or will within its cadence. Confirm with a read-only `outlook-mailbox-info` or `outlook-mailbox-list` check. You only need `outlook-account-register-poll` if that confirmation shows the mailbox still unregistered and you want to force the harvest immediately rather than wait for the next dispatcher tick.
|
|
37
37
|
|
|
38
|
-
**
|
|
38
|
+
**The server drives every issued code to a terminal outcome.** Once `outlook-account-register` has issued a code, the completion dispatcher polls it to `registered`, `expired`, or `denied` on its own, so a code is never left hanging and the leftover-pending state that made the next `outlook-account-register` return `register-in-progress` no longer occurs after a normal sign-in.
|
|
39
39
|
|
|
40
40
|
Subsequent tool calls use the persisted refresh token to mint access tokens transparently. Re-register is only needed if the refresh token expires (90 days) or the user revokes consent.
|
|
41
41
|
|
|
@@ -49,8 +49,8 @@ The revoke path below is scoped to one specific, visible failure. It is not a ge
|
|
|
49
49
|
|
|
50
50
|
## Reading mail
|
|
51
51
|
|
|
52
|
-
- `outlook-mail-list` —
|
|
53
|
-
- `outlook-mail-search query=<keyword>` — Microsoft Graph `$search` over the mailbox
|
|
52
|
+
- `outlook-mail-list` — mail newest-first, default top=25, folder=Inbox. Returns Microsoft's short `bodyPreview` (~255 chars) for cheap triage. Add `since`/`before` (ISO date-times) for a date window. To reach mail older than the newest page, pass the response's `nextCursor` back as `cursor` — repeat until `nextCursor` is null. Filter by sender or subject via `outlook-mail-search`.
|
|
53
|
+
- `outlook-mail-search query=<keyword>` — Microsoft Graph `$search` (KQL) over the mailbox; same preview-only shape as the list. Put filters in the query: `from:addr`, `to:addr`, `subject:text`, `received>=2024-01-01`, or free text. Page with `nextCursor` → `cursor` like the list. (Graph forbids `$search`+date-`$filter`, so a strict date window is on `outlook-mail-list`.)
|
|
54
54
|
- `outlook-mail-fetch-body messageId=<id>` — the COMPLETE body of one message (HTML decoded to text, no preview cap). This is the full-read path: `outlook-mail-list` / `outlook-mail-search` return previews only, so when you must read or act on a message's actual content, fetch the body by its id. Also returns the envelope (from, to, cc, subject, date, conversationId).
|
|
55
55
|
|
|
56
56
|
## Replying and deleting
|
|
@@ -98,7 +98,7 @@ All calendar writes need the `Calendars.ReadWrite` consent (see setup above). Ti
|
|
|
98
98
|
|
|
99
99
|
| Error | Meaning | Operator action |
|
|
100
100
|
|---|---|---|
|
|
101
|
-
| `auth-required` | Account not registered, or refresh token expired | Run `outlook-account-register
|
|
101
|
+
| `auth-required` | Account not registered, or refresh token expired | Run `outlook-account-register`; the server completes the sign-in once the operator consents |
|
|
102
102
|
| `Calendars.ReadWrite scope not granted` | Mailbox last consented on the old read-only calendar scope | Re-run `outlook-account-register` + `outlook-account-register-poll` to re-consent with calendar write |
|
|
103
103
|
| `Outlook token refresh failed` | Network down or refresh token invalidated | Verify connectivity; re-run register if persistent |
|
|
104
104
|
| `Microsoft Graph does not support on-premises Exchange` | Mailbox is on hybrid Exchange | Use the `email` plugin (IMAP) |
|
|
@@ -154,7 +154,7 @@ Dispatch results are recorded on the Event node (`lastDispatchResult`, `lastDisp
|
|
|
154
154
|
|
|
155
155
|
It is **armed by the always-running `platform/ui` server on an interval**, because the Pi has no other periodic surface (the same gap `check-due-events` has). A PID lock at `<configDir>/reconcile-bookings.lock` prevents overlapping runs. It registers **no agent tool** — there is nothing for the agent to call — so the tool-surface registries are untouched.
|
|
156
156
|
|
|
157
|
-
Env: `PLATFORM_ROOT`, `NEO4J_URI` (and `NEO4J_PASSWORD` or `config/.neo4j-password`). Per account it reads `data/accounts/<id>/calendar-availability.json` (for `bookingDbName`)
|
|
157
|
+
Env: `PLATFORM_ROOT`, `NEO4J_URI` (and `NEO4J_PASSWORD` or `config/.neo4j-password`). Per account it reads `data/accounts/<id>/calendar-availability.json` (for `bookingDbName`). The Cloudflare credential is read house-only from `config/cloudflare-house.env`; that credential is a minter, so the calendar mints a `calendar-d1` (D1-only) token from it via `cf-token.sh` and shells `wrangler` for the D1 reads/writes on that scoped token, never the minter directly.
|
|
158
158
|
|
|
159
159
|
Observability: one `[calendar-booking]` line per step keyed by `bookingId` (`reconcile-claim`, `meeting-write`, `notify`, `booked`), and one `[calendar-reconcile] account=… pendingUnreconciled=… orphanMeetings=…` audit line per account per run. A `pendingUnreconciled` that persists across runs means reconcile is stalled; `orphanMeetings` means a booking meeting has no backing D1 row.
|
|
160
160
|
|
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"house-scoped-token.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/house-scoped-token.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Task 1670 — the calendar mints (then reuses) a D1-only scoped token from the
|
|
2
|
+
// house minter via cf-token.sh. This guards the readback wrapper: it shells
|
|
3
|
+
// cf-token.sh and returns the value of the persisted key, never the minter.
|
|
4
|
+
import { describe, it, expect } from "vitest";
|
|
5
|
+
import { mkdtempSync, writeFileSync, appendFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { resolveHouseScopedToken } from "../house-scoped-token.js";
|
|
9
|
+
function houseFile(contents) {
|
|
10
|
+
const dir = mkdtempSync(join(tmpdir(), "cal-hst-"));
|
|
11
|
+
const p = join(dir, "cloudflare-house.env");
|
|
12
|
+
writeFileSync(p, contents);
|
|
13
|
+
return p;
|
|
14
|
+
}
|
|
15
|
+
describe("resolveHouseScopedToken (calendar)", () => {
|
|
16
|
+
it("mints and reads back the calendar-d1 token", () => {
|
|
17
|
+
const p = houseFile("CLOUDFLARE_API_TOKEN=cfat_minter\nCLOUDFLARE_ACCOUNT_ID=acc\n");
|
|
18
|
+
const run = (_cmd, args) => {
|
|
19
|
+
expect(args[1]).toBe("calendar-d1");
|
|
20
|
+
appendFileSync(p, "CF_CALENDAR_D1_TOKEN=cal_tok\n");
|
|
21
|
+
return "CF_CALENDAR_D1_TOKEN\n";
|
|
22
|
+
};
|
|
23
|
+
expect(resolveHouseScopedToken("calendar-d1", p, "/x/cf-token.sh", run)).toBe("cal_tok");
|
|
24
|
+
});
|
|
25
|
+
it("reuses a pre-existing key", () => {
|
|
26
|
+
const p = houseFile("CLOUDFLARE_API_TOKEN=cfat_minter\nCLOUDFLARE_ACCOUNT_ID=acc\nCF_CALENDAR_D1_TOKEN=already\n");
|
|
27
|
+
const run = () => "CF_CALENDAR_D1_TOKEN\n";
|
|
28
|
+
expect(resolveHouseScopedToken("calendar-d1", p, "/x/cf-token.sh", run)).toBe("already");
|
|
29
|
+
});
|
|
30
|
+
it("throws when the persisted key is absent after the run", () => {
|
|
31
|
+
const p = houseFile("CLOUDFLARE_API_TOKEN=cfat_minter\nCLOUDFLARE_ACCOUNT_ID=acc\n");
|
|
32
|
+
const run = () => "CF_CALENDAR_D1_TOKEN\n"; // writes nothing
|
|
33
|
+
expect(() => resolveHouseScopedToken("calendar-d1", p, "/x/cf-token.sh", run)).toThrow();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=house-scoped-token.test.js.map
|
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/house-scoped-token.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"house-scoped-token.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/house-scoped-token.test.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,SAAS,SAAS,CAAC,QAAgB;IACjC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IAC5C,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,GAAG,SAAS,CAAC,+DAA+D,CAAC,CAAC;QACrF,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,IAAc,EAAE,EAAE;YAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACpC,cAAc,CAAC,CAAC,EAAE,gCAAgC,CAAC,CAAC;YACpD,OAAO,wBAAwB,CAAC;QAClC,CAAC,CAAC;QACF,MAAM,CAAC,uBAAuB,CAAC,aAAa,EAAE,CAAC,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,SAAS,CAAC,6FAA6F,CAAC,CAAC;QACnH,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,wBAAwB,CAAC;QAC3C,MAAM,CAAC,uBAAuB,CAAC,aAAa,EAAE,CAAC,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,GAAG,SAAS,CAAC,+DAA+D,CAAC,CAAC;QACrF,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,wBAAwB,CAAC,CAAC,iBAAiB;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,aAAa,EAAE,CAAC,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC3F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type RunSync = (cmd: string, args: string[]) => string;
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a scoped data token (e.g. "calendar-d1" = D1 only) from the house
|
|
4
|
+
* minter. Shells cf-token.sh, which mints or reuses the scope and persists the
|
|
5
|
+
* key into the house env file, echoing the key name; reads that key back and
|
|
6
|
+
* returns its value. Throws if the key is absent after the run.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveHouseScopedToken(scope: string, houseEnvPath: string, cfTokenShPath: string, run?: RunSync): string;
|
|
9
|
+
//# sourceMappingURL=house-scoped-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"house-scoped-token.d.ts","sourceRoot":"","sources":["../../src/lib/house-scoped-token.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;AAkB9D;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,OAAoB,GACxB,MAAM,CAWR"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Task 1670 — the house Cloudflare credential is a minter. The booking calendar
|
|
2
|
+
// mints (then reuses) a D1-only scoped token from it via cf-token.sh, the single
|
|
3
|
+
// mint/reuse state machine. Kept local to the scheduling plugin because it
|
|
4
|
+
// cannot import the storage-broker lib; only the ~10-line shell-and-readback
|
|
5
|
+
// wrapper is mirrored — the mint logic itself lives only in cf-token.sh.
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
const defaultRun = (cmd, args) => {
|
|
9
|
+
const r = spawnSync(cmd, args, { encoding: "utf-8", timeout: 60_000 });
|
|
10
|
+
if (r.status !== 0) {
|
|
11
|
+
throw new Error(`${cmd} ${args.join(" ")} failed (status ${r.status ?? "null"}): ${r.stderr ?? ""}`);
|
|
12
|
+
}
|
|
13
|
+
return r.stdout;
|
|
14
|
+
};
|
|
15
|
+
function readKey(path, key) {
|
|
16
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
17
|
+
const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
|
|
18
|
+
if (m && m[1] === key)
|
|
19
|
+
return m[2].trim();
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a scoped data token (e.g. "calendar-d1" = D1 only) from the house
|
|
25
|
+
* minter. Shells cf-token.sh, which mints or reuses the scope and persists the
|
|
26
|
+
* key into the house env file, echoing the key name; reads that key back and
|
|
27
|
+
* returns its value. Throws if the key is absent after the run.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveHouseScopedToken(scope, houseEnvPath, cfTokenShPath, run = defaultRun) {
|
|
30
|
+
const preexisting = readKey(houseEnvPath, keyForScope(scope)) !== undefined;
|
|
31
|
+
const out = run("bash", [cfTokenShPath, scope, houseEnvPath]);
|
|
32
|
+
const keyName = out.trim().split("\n").pop()?.trim() ?? "";
|
|
33
|
+
if (!keyName)
|
|
34
|
+
throw new Error(`scheduling: cf-token.sh ${scope} returned no key name`);
|
|
35
|
+
const value = readKey(houseEnvPath, keyName);
|
|
36
|
+
if (!value)
|
|
37
|
+
throw new Error(`scheduling: scoped token ${keyName} absent in ${houseEnvPath} after mint`);
|
|
38
|
+
console.error(`[calendar] op=house-scoped-token src=house scope=${scope} action=${preexisting ? "reuse" : "mint"} result=active`);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function keyForScope(scope) {
|
|
42
|
+
switch (scope) {
|
|
43
|
+
case "calendar-d1":
|
|
44
|
+
return "CF_CALENDAR_D1_TOKEN";
|
|
45
|
+
case "storage":
|
|
46
|
+
return "CF_STORAGE_TOKEN";
|
|
47
|
+
default:
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=house-scoped-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"house-scoped-token.js","sourceRoot":"","sources":["../../src/lib/house-scoped-token.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,iFAAiF;AACjF,2EAA2E;AAC3E,6EAA6E;AAC7E,yEAAyE;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,MAAM,UAAU,GAAY,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;IACxC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC;AAClB,CAAC,CAAC;AAEF,SAAS,OAAO,CAAC,IAAY,EAAE,GAAW;IACxC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAa,EACb,YAAoB,EACpB,aAAqB,EACrB,MAAe,UAAU;IAEzB,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,SAAS,CAAC;IAC5E,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3D,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,uBAAuB,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,cAAc,YAAY,aAAa,CAAC,CAAC;IACxG,OAAO,CAAC,KAAK,CACX,oDAAoD,KAAK,WAAW,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,gBAAgB,CACnH,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,sBAAsB,CAAC;QAChC,KAAK,SAAS;YACZ,OAAO,kBAAkB,CAAC;QAC5B;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -27,6 +27,7 @@ import { spawnSync } from "node:child_process";
|
|
|
27
27
|
import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
28
28
|
import { resolve, join, basename } from "node:path";
|
|
29
29
|
import { homedir, tmpdir } from "node:os";
|
|
30
|
+
import { resolveHouseScopedToken } from "../lib/house-scoped-token.js";
|
|
30
31
|
function resolveConfigDir() {
|
|
31
32
|
const platformRoot = process.env.PLATFORM_ROOT;
|
|
32
33
|
if (!platformRoot)
|
|
@@ -148,12 +149,25 @@ async function main() {
|
|
|
148
149
|
console.error(`[calendar-availability] op=publish accountId=${accountId} result=skipped reason=no-platform-root`);
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
151
|
-
const
|
|
152
|
+
const houseEnvPath = join(platformRoot, "config", "cloudflare-house.env");
|
|
153
|
+
const houseCred = readEnvFile(houseEnvPath);
|
|
152
154
|
const token = houseCred.CLOUDFLARE_API_TOKEN;
|
|
153
155
|
if (!token) {
|
|
154
156
|
console.error(`[calendar-availability] op=publish accountId=${accountId} result=skipped reason=no-house-cloudflare-credential`);
|
|
155
157
|
return;
|
|
156
158
|
}
|
|
159
|
+
// Task 1670 — the house credential is a minter; mint (then reuse) a D1-only
|
|
160
|
+
// scoped token from it via cf-token.sh and run wrangler on THAT, never the
|
|
161
|
+
// minter directly (a minter returns 10000 on wrangler d1).
|
|
162
|
+
const cfTokenSh = join(platformRoot, "plugins/cloudflare/bin/cf-token.sh");
|
|
163
|
+
let scopedToken;
|
|
164
|
+
try {
|
|
165
|
+
scopedToken = resolveHouseScopedToken("calendar-d1", houseEnvPath, cfTokenSh);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
console.error(`[calendar-availability] op=publish accountId=${accountId} result=skipped reason=scoped-token-mint-failed err="${err.message}"`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
157
171
|
const port = process.env.MAXY_UI_INTERNAL_PORT;
|
|
158
172
|
if (!port) {
|
|
159
173
|
console.error(`[calendar-availability] op=publish accountId=${accountId} result=error reason=no-internal-port`);
|
|
@@ -215,7 +229,7 @@ ON CONFLICT(id) DO UPDATE SET payload=excluded.payload, updatedAt=excluded.updat
|
|
|
215
229
|
try {
|
|
216
230
|
writeFileSync(sqlFile, sql);
|
|
217
231
|
const wranglerEnv = {
|
|
218
|
-
CLOUDFLARE_API_TOKEN:
|
|
232
|
+
CLOUDFLARE_API_TOKEN: scopedToken,
|
|
219
233
|
...(houseCred.CLOUDFLARE_ACCOUNT_ID ? { CLOUDFLARE_ACCOUNT_ID: houseCred.CLOUDFLARE_ACCOUNT_ID } : {}),
|
|
220
234
|
};
|
|
221
235
|
const proc = spawnSync("npx", ["wrangler", "d1", "execute", dbName, "--remote", "--file", sqlFile], {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-availability.js","sourceRoot":"","sources":["../../src/scripts/publish-availability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9G,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-availability.js","sourceRoot":"","sources":["../../src/scripts/publish-availability.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,7 @@ import { homedir } from "node:os";
|
|
|
29
29
|
import { reconcileOne, auditCounts, ensureConnectorSyncEvent, countPublishedConflicts } from "../lib/booking-reconcile.js";
|
|
30
30
|
import { notifyBooking } from "../lib/booking-notify.js";
|
|
31
31
|
import { buildD1Command } from "../lib/d1-command.js";
|
|
32
|
+
import { resolveHouseScopedToken } from "../lib/house-scoped-token.js";
|
|
32
33
|
function resolveConfigDir() {
|
|
33
34
|
const platformRoot = process.env.PLATFORM_ROOT;
|
|
34
35
|
if (!platformRoot)
|
|
@@ -323,17 +324,30 @@ async function main() {
|
|
|
323
324
|
if (accountIds.length === 0)
|
|
324
325
|
return;
|
|
325
326
|
// Task 1631 — the account-wide Cloudflare credential lives house-only.
|
|
326
|
-
const
|
|
327
|
+
const houseEnvPath = join(platformRoot, "config", "cloudflare-house.env");
|
|
328
|
+
const houseCred = readEnvFile(houseEnvPath);
|
|
327
329
|
const houseToken = houseCred.CLOUDFLARE_API_TOKEN;
|
|
328
330
|
if (!houseToken) {
|
|
329
331
|
console.error("[calendar-reconcile] skip reason=no-house-cloudflare-credential");
|
|
330
332
|
return;
|
|
331
333
|
}
|
|
332
334
|
const houseAccountId = houseCred.CLOUDFLARE_ACCOUNT_ID;
|
|
335
|
+
// Task 1670 — the house credential is a minter; mint (then reuse) a D1-only
|
|
336
|
+
// scoped token from it via cf-token.sh and run wrangler on THAT, never the
|
|
337
|
+
// minter directly (a minter returns 10000 on wrangler d1).
|
|
338
|
+
const cfTokenSh = join(platformRoot, "plugins/cloudflare/bin/cf-token.sh");
|
|
339
|
+
let scopedToken;
|
|
340
|
+
try {
|
|
341
|
+
scopedToken = resolveHouseScopedToken("calendar-d1", houseEnvPath, cfTokenSh);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
console.error(`[calendar-reconcile] skip reason=scoped-token-mint-failed err="${err.message}"`);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
333
347
|
driver = connectNeo4j();
|
|
334
348
|
for (const accountId of accountIds) {
|
|
335
349
|
try {
|
|
336
|
-
await reconcileAccount(driver, accountId, join(accountsDir, accountId),
|
|
350
|
+
await reconcileAccount(driver, accountId, join(accountsDir, accountId), scopedToken, houseAccountId);
|
|
337
351
|
}
|
|
338
352
|
catch (err) {
|
|
339
353
|
console.error(`[calendar-reconcile] account=${accountId} run-failed err="${err.message}"`);
|