@rubytech/create-maxy-code 0.1.439 → 0.1.441
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/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +41 -12
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +15 -5
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/functions/api/calendar/free-busy.ts +152 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/index.html +6 -3
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +11 -0
- package/payload/platform/plugins/docs/references/admin-identity-gate.md +32 -17
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/calendar-booking.md +1 -1
- package/payload/platform/plugins/docs/references/graph.md +19 -3
- package/payload/platform/plugins/docs/references/internals.md +2 -2
- package/payload/platform/plugins/docs/references/outlook-guide.md +9 -4
- package/payload/platform/plugins/docs/references/troubleshooting.md +8 -0
- package/payload/platform/plugins/graph/.claude-plugin/plugin.json +19 -0
- package/payload/platform/plugins/graph/PLUGIN.md +10 -4
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +7 -3
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js +100 -10
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.js +55 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +64 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js +193 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +58 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +81 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +171 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +16 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +25 -3
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +119 -50
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +8 -4
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +22 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +17 -0
- 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 +84 -21
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +28 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -0
- package/payload/platform/plugins/outlook/references/auth.md +36 -8
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +15 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts +27 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +241 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -0
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +100 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +207 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.sh +33 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +7 -0
- package/payload/platform/scripts/setup-account.sh +10 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.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 +6 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.d.ts +7 -6
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.js +56 -7
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-UGPQCVIW.js → chunk-WC4WJR6X.js} +0 -6
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-DeR71H29.js → AdminLoginScreens-CukwQufW.js} +1 -1
- package/payload/server/public/assets/AdminShell-BwEBH6tT.js +2 -0
- package/payload/server/public/assets/{admin-C15h-NL0.js → admin-CdFRCUUZ.js} +1 -1
- package/payload/server/public/assets/{browser-B7xQLIRK.js → browser-BWR59IkB.js} +1 -1
- package/payload/server/public/assets/{calendar-A-vGm6pL.js → calendar-kuTcxX1t.js} +1 -1
- package/payload/server/public/assets/chat-ejnq2rck.js +1 -0
- package/payload/server/public/assets/data-dZbOyLdT.js +1 -0
- package/payload/server/public/assets/{graph-D0orIRAh.js → graph-CboWM2_-.js} +2 -2
- package/payload/server/public/assets/{operator-DZzuotDB.js → operator-oSaB1mya.js} +1 -1
- package/payload/server/public/assets/{page-Ck_pLhAk.js → page-DEkI-Gl1.js} +1 -1
- package/payload/server/public/assets/{page-3g0A19Rv.js → page-DMeJHVfA.js} +5 -5
- package/payload/server/public/assets/{public-WFUQw9AD.js → public-C54tl6V4.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-CSk9KjhY.js → useCopyFeedback-DHoYHiK9.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-DCyJQkFK.js → useVoiceRecorder-b7HzTFs0.js} +1 -1
- package/payload/server/public/browser.html +2 -2
- package/payload/server/public/calendar.html +2 -2
- package/payload/server/public/chat.html +5 -5
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +5 -5
- package/payload/server/public/operator.html +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +255 -112
- package/payload/server/public/assets/AdminShell-DlAVQUda.js +0 -2
- package/payload/server/public/assets/chat-DAae6Z51.js +0 -1
- package/payload/server/public/assets/data-BNWpKx1d.js +0 -1
|
@@ -7,6 +7,19 @@ import { log } from "../lib/log.js";
|
|
|
7
7
|
* the result. Returns immediately — no blocking wait.
|
|
8
8
|
*/
|
|
9
9
|
export async function runAccountRegisterStart(args) {
|
|
10
|
+
// Single-slot pending: one device-code flow in flight per account. A live
|
|
11
|
+
// pending entry means a registration is mid-sign-in; refuse rather than
|
|
12
|
+
// overwrite its device code (which would strand the operator's open browser).
|
|
13
|
+
// An expired entry is stale and gets replaced. Genuinely-concurrent flows are
|
|
14
|
+
// out of scope — see .tasks/1594.
|
|
15
|
+
const existing = args.pendingStore.read();
|
|
16
|
+
if (existing && Date.now() <= existing.expiresAtMs) {
|
|
17
|
+
log({ event: "register-in-progress", account: args.accountId });
|
|
18
|
+
return {
|
|
19
|
+
status: "in-progress",
|
|
20
|
+
message: "An Outlook registration is already in progress for this account. Finish that sign-in at microsoft.com/devicelogin, or wait for its code to expire, before starting another.",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
10
23
|
const start = await startDeviceCode({ clientId: args.clientId, tenantId: args.tenantId });
|
|
11
24
|
const now = Date.now();
|
|
12
25
|
args.pendingStore.write({
|
|
@@ -88,17 +101,23 @@ export async function runAccountRegisterPoll(args) {
|
|
|
88
101
|
}
|
|
89
102
|
const me = (await meResp.json());
|
|
90
103
|
const graphUserId = me.id ?? me.mail ?? me.userPrincipalName ?? "unknown";
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
const mail = me.mail ?? me.userPrincipalName ?? null;
|
|
105
|
+
// Store under the resolved mailbox identity, so a second registration adds a
|
|
106
|
+
// mailbox rather than overwriting the first. Re-registering the same
|
|
107
|
+
// graphUserId updates that mailbox in place (no duplicate).
|
|
108
|
+
const store = args.registry.storeFor(graphUserId);
|
|
109
|
+
store.store(tokenResponse.access_token, tokenResponse.refresh_token ?? null, tokenResponse.expires_in, { graphUserId, mail, scopes });
|
|
110
|
+
const tokenExpSec = Math.floor((store.read()?.accessTokenExpiry ?? 0) / 1000);
|
|
93
111
|
log({
|
|
94
112
|
event: "auth-ok",
|
|
95
113
|
account: args.accountId,
|
|
96
114
|
graphUserId,
|
|
115
|
+
mail: mail ?? "",
|
|
97
116
|
scopes: scopes.join(","),
|
|
98
117
|
tokenExpSec,
|
|
99
118
|
});
|
|
100
119
|
clearPending(args);
|
|
101
|
-
return { status: "registered", graphUserId, scopes, tokenExpSec };
|
|
120
|
+
return { status: "registered", graphUserId, mail, scopes, tokenExpSec };
|
|
102
121
|
}
|
|
103
122
|
/** Verified clear + census on every terminal poll outcome. */
|
|
104
123
|
function clearPending(args) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG1E,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,23 @@ export interface MailListArgs {
|
|
|
3
3
|
top?: number;
|
|
4
4
|
folder?: string;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Map a caller-supplied `folder` value to the Graph `/me/mailFolders/{id}`
|
|
8
|
+
* path segment.
|
|
9
|
+
*
|
|
10
|
+
* Graph accepts only a well-known token (a single word, no spaces:
|
|
11
|
+
* `inbox`, `sentitems`, `drafts`, `deleteditems`, `junkemail`, `archive`,
|
|
12
|
+
* `outbox`) or a real folder id in that segment. A human display name such as
|
|
13
|
+
* "Sent Items" is neither, so Graph rejects it with "Id is malformed". This
|
|
14
|
+
* normalizes the full well-known set plus common aliases — case-insensitively
|
|
15
|
+
* and space-insensitively — to the Graph token. Any value not in the alias
|
|
16
|
+
* table is assumed to be a raw folder id and returned unchanged (`asRawId`),
|
|
17
|
+
* preserving the prior pass-through behaviour.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveFolder(folder: string): {
|
|
20
|
+
token: string;
|
|
21
|
+
asRawId: boolean;
|
|
22
|
+
};
|
|
6
23
|
export interface MailListItem {
|
|
7
24
|
id: string;
|
|
8
25
|
subject: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-list.d.ts","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIhE,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-list.d.ts","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIhE,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IAMb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAUjF;AAsBD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAiBD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiDzB"}
|
|
@@ -1,30 +1,93 @@
|
|
|
1
1
|
import { callGraph } from "../lib/graph-client.js";
|
|
2
2
|
import { log } from "../lib/log.js";
|
|
3
|
+
/**
|
|
4
|
+
* Map a caller-supplied `folder` value to the Graph `/me/mailFolders/{id}`
|
|
5
|
+
* path segment.
|
|
6
|
+
*
|
|
7
|
+
* Graph accepts only a well-known token (a single word, no spaces:
|
|
8
|
+
* `inbox`, `sentitems`, `drafts`, `deleteditems`, `junkemail`, `archive`,
|
|
9
|
+
* `outbox`) or a real folder id in that segment. A human display name such as
|
|
10
|
+
* "Sent Items" is neither, so Graph rejects it with "Id is malformed". This
|
|
11
|
+
* normalizes the full well-known set plus common aliases — case-insensitively
|
|
12
|
+
* and space-insensitively — to the Graph token. Any value not in the alias
|
|
13
|
+
* table is assumed to be a raw folder id and returned unchanged (`asRawId`),
|
|
14
|
+
* preserving the prior pass-through behaviour.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveFolder(folder) {
|
|
17
|
+
const key = folder.toLowerCase().replace(/\s+/g, "");
|
|
18
|
+
// Own-key check only: a bare `WELL_KNOWN_ALIASES[key]` would also read
|
|
19
|
+
// inherited members, so `folder` values like "constructor" or "__proto__"
|
|
20
|
+
// would resolve to an Object.prototype member instead of passing through as
|
|
21
|
+
// raw ids.
|
|
22
|
+
if (Object.hasOwn(WELL_KNOWN_ALIASES, key)) {
|
|
23
|
+
return { token: WELL_KNOWN_ALIASES[key], asRawId: false };
|
|
24
|
+
}
|
|
25
|
+
return { token: folder, asRawId: true };
|
|
26
|
+
}
|
|
27
|
+
// Lookup keys are already lowercased and space-stripped. Inbox maps to the
|
|
28
|
+
// capitalized "Inbox" segment the tool has always used (Graph is
|
|
29
|
+
// case-insensitive on well-known names); the rest map to the lowercase Graph
|
|
30
|
+
// tokens. "" (and whitespace-only) collapses to the key "" → Inbox, folding in
|
|
31
|
+
// the former lone-inbox special case.
|
|
32
|
+
const WELL_KNOWN_ALIASES = {
|
|
33
|
+
"": "Inbox",
|
|
34
|
+
inbox: "Inbox",
|
|
35
|
+
sentitems: "sentitems",
|
|
36
|
+
sent: "sentitems",
|
|
37
|
+
drafts: "drafts",
|
|
38
|
+
deleteditems: "deleteditems",
|
|
39
|
+
trash: "deleteditems",
|
|
40
|
+
junkemail: "junkemail",
|
|
41
|
+
junk: "junkemail",
|
|
42
|
+
spam: "junkemail",
|
|
43
|
+
archive: "archive",
|
|
44
|
+
outbox: "outbox",
|
|
45
|
+
};
|
|
3
46
|
const FIELDS = "id,subject,from,receivedDateTime,bodyPreview,isRead";
|
|
4
47
|
export async function runMailList(config, args) {
|
|
5
48
|
const top = clampTop(args.top, 25);
|
|
6
|
-
const
|
|
49
|
+
const folderIn = args.folder ?? "Inbox";
|
|
50
|
+
const { token: folderResolved, asRawId } = resolveFolder(folderIn);
|
|
7
51
|
const startMs = Date.now();
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
52
|
+
try {
|
|
53
|
+
const result = await callGraph(config, async (client) => {
|
|
54
|
+
const path = `/me/mailFolders/${encodeURIComponent(folderResolved)}/messages`;
|
|
55
|
+
return (await client
|
|
56
|
+
.api(path)
|
|
57
|
+
.top(top)
|
|
58
|
+
.orderby("receivedDateTime DESC")
|
|
59
|
+
.select(FIELDS)
|
|
60
|
+
.get());
|
|
61
|
+
}, { tool: "mail-list" });
|
|
62
|
+
const items = result.value.map(shapeMessage);
|
|
63
|
+
log({
|
|
64
|
+
event: "mail-list",
|
|
65
|
+
op: "resolve",
|
|
66
|
+
account: config.accountId,
|
|
67
|
+
folderIn,
|
|
68
|
+
folderResolved,
|
|
69
|
+
asRawId,
|
|
70
|
+
count: items.length,
|
|
71
|
+
elapsedMs: Date.now() - startMs,
|
|
72
|
+
});
|
|
73
|
+
return items;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
// callGraph already logged the graph-error line (status/code, e.g. the 400
|
|
77
|
+
// "Id is malformed"); this line attaches the folder resolution so the
|
|
78
|
+
// failing input and the token it mapped to are visible on the error path.
|
|
79
|
+
log({
|
|
80
|
+
event: "mail-list",
|
|
81
|
+
op: "resolve",
|
|
82
|
+
account: config.accountId,
|
|
83
|
+
folderIn,
|
|
84
|
+
folderResolved,
|
|
85
|
+
asRawId,
|
|
86
|
+
error: err.message,
|
|
87
|
+
elapsedMs: Date.now() - startMs,
|
|
88
|
+
});
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
28
91
|
}
|
|
29
92
|
function shapeMessage(msg) {
|
|
30
93
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-list.js","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-list.js","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface MailboxListItem {
|
|
2
|
+
/** Opaque directory handle under mailboxes/ — stable even when unreadable. */
|
|
3
|
+
mailboxKey: string;
|
|
4
|
+
/** The mailbox email address, when the blob is readable. */
|
|
5
|
+
mailbox: string | null;
|
|
6
|
+
graphUserId: string | null;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
tokenExpSec: number | null;
|
|
9
|
+
refreshExpired: boolean;
|
|
10
|
+
readable: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MailboxListResult {
|
|
13
|
+
count: number;
|
|
14
|
+
/** How many blobs are on disk but do not decrypt/parse — an orphaned store. */
|
|
15
|
+
unreadable: number;
|
|
16
|
+
mailboxes: MailboxListItem[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* List every Outlook mailbox attached to this account. Local only — reads the
|
|
20
|
+
* on-disk stores, never Graph — so it reconciles what is stored against what the
|
|
21
|
+
* agent can address even when Graph is unreachable. An unreadable blob is
|
|
22
|
+
* surfaced (`readable:false`) rather than dropped, closing the no-event blind
|
|
23
|
+
* spot where a mailbox silently falls out of addressability.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runMailboxList(accountId: string, accountsDir: string): MailboxListResult;
|
|
26
|
+
//# sourceMappingURL=mailbox-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox-list.d.ts","sourceRoot":"","sources":["../../src/tools/mailbox-list.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,iBAAiB,CAiBxF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MailboxRegistry } from "../auth/mailbox-registry.js";
|
|
2
|
+
import { log } from "../lib/log.js";
|
|
3
|
+
/**
|
|
4
|
+
* List every Outlook mailbox attached to this account. Local only — reads the
|
|
5
|
+
* on-disk stores, never Graph — so it reconciles what is stored against what the
|
|
6
|
+
* agent can address even when Graph is unreachable. An unreadable blob is
|
|
7
|
+
* surfaced (`readable:false`) rather than dropped, closing the no-event blind
|
|
8
|
+
* spot where a mailbox silently falls out of addressability.
|
|
9
|
+
*/
|
|
10
|
+
export function runMailboxList(accountId, accountsDir) {
|
|
11
|
+
const boxes = new MailboxRegistry(accountId, accountsDir).list();
|
|
12
|
+
const unreadable = boxes.filter((b) => !b.readable).length;
|
|
13
|
+
log({ event: "mailbox-list", account: accountId, count: boxes.length, unreadable });
|
|
14
|
+
return {
|
|
15
|
+
count: boxes.length,
|
|
16
|
+
unreadable,
|
|
17
|
+
mailboxes: boxes.map((b) => ({
|
|
18
|
+
mailboxKey: b.mailboxKey,
|
|
19
|
+
mailbox: b.mail,
|
|
20
|
+
graphUserId: b.graphUserId,
|
|
21
|
+
scopes: b.scopes,
|
|
22
|
+
tokenExpSec: b.tokenExpSec,
|
|
23
|
+
refreshExpired: b.refreshExpired,
|
|
24
|
+
readable: b.readable,
|
|
25
|
+
})),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=mailbox-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox-list.js","sourceRoot":"","sources":["../../src/tools/mailbox-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAqBpC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,WAAmB;IACnE,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;IACjE,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC3D,GAAG,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACpF,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,UAAU;QACV,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,OAAO,EAAE,CAAC,CAAC,IAAI;YACf,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,cAAc,EAAE,CAAC,CAAC,cAAc;YAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|
|
@@ -72,8 +72,8 @@ operator plugin
|
|
|
72
72
|
| | < authorization_pending → pending |
|
|
73
73
|
| | < tokens (once consented) → success |
|
|
74
74
|
| | <----------------------------------- |
|
|
75
|
-
| |
|
|
76
|
-
| |
|
|
75
|
+
| | GET /me (resolve graphUserId + mail) |
|
|
76
|
+
| | encrypt → write mailboxes/<id>/tokens.enc |
|
|
77
77
|
| | clear pending (verified re-stat) |
|
|
78
78
|
| { status: "registered", graphUserId, ... } | |
|
|
79
79
|
|<---------------------------------------------| |
|
|
@@ -83,16 +83,33 @@ operator plugin
|
|
|
83
83
|
|
|
84
84
|
## Token store layout
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
One account can hold several mailboxes. Each mailbox owns its own `tokens.enc`
|
|
87
|
+
under `mailboxes/<graphUserId>/`, and they share the one account-level AES `.key`.
|
|
88
|
+
Account isolation is unchanged — the key is per-account, never shared across
|
|
89
|
+
accounts — while mailboxes within one account share it. Per-account, mode 0700
|
|
90
|
+
directories + mode 0600 files:
|
|
87
91
|
|
|
88
92
|
```
|
|
89
93
|
data/accounts/<accountId>/secrets/outlook/
|
|
90
|
-
├── .key
|
|
91
|
-
├──
|
|
92
|
-
|
|
94
|
+
├── .key # 32 random bytes, base64 — the AES-256-CBC key, shared by every mailbox on this account
|
|
95
|
+
├── mailboxes/
|
|
96
|
+
│ ├── <graphUserId-A>/tokens.enc # AES-256-CBC "<iv-hex>:<cipher-hex>" of mailbox A's token JSON blob
|
|
97
|
+
│ └── <graphUserId-B>/tokens.enc # mailbox B — coexists, never overwritten by A
|
|
98
|
+
└── pending-devicecode.enc # transient — the device_code between register + poll; cleared on any terminal outcome
|
|
93
99
|
```
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
**Migration.** A pre-multi-mailbox install has a single `tokens.enc` at the
|
|
102
|
+
account root. On first read the registry moves it into
|
|
103
|
+
`mailboxes/<graphUserId>/tokens.enc`. Because the AES key is unchanged, the
|
|
104
|
+
ciphertext is valid as-is — the migration is a file move, never a re-encrypt,
|
|
105
|
+
and never forces a re-auth.
|
|
106
|
+
|
|
107
|
+
**One registration at a time.** The pending file is single-slot per account and
|
|
108
|
+
reuses the same `.key`. `outlook-account-register` refuses with an `in-progress`
|
|
109
|
+
signal when a live device-code flow already exists, rather than overwriting it.
|
|
110
|
+
The entry is removed (verified by re-stat) when polling reaches `registered`,
|
|
111
|
+
`expired`, or `denied`, so a device_code never lingers. Genuinely-concurrent
|
|
112
|
+
registrations are out of scope — see `.tasks/1594`.
|
|
96
113
|
|
|
97
114
|
The JSON blob shape:
|
|
98
115
|
|
|
@@ -103,13 +120,24 @@ The JSON blob shape:
|
|
|
103
120
|
accessTokenExpiry: number; // unix ms
|
|
104
121
|
refreshTokenExpiry: number; // unix ms; ~90 days from issue
|
|
105
122
|
lastRefresh: number; // unix ms
|
|
106
|
-
graphUserId: string | null; // from /me.id
|
|
123
|
+
graphUserId: string | null; // from /me.id — also the mailbox directory key
|
|
124
|
+
mail: string | null; // from /me.mail (or userPrincipalName) — the selectable address
|
|
107
125
|
scopes: string[]; // granted scopes from token response
|
|
108
126
|
}
|
|
109
127
|
```
|
|
110
128
|
|
|
111
129
|
Atomic write: temp + rename. Either old or new tokens, never partial.
|
|
112
130
|
|
|
131
|
+
## Mailbox selection
|
|
132
|
+
|
|
133
|
+
Every operational tool takes an optional `mailbox` argument (an email address or
|
|
134
|
+
graphUserId). Resolution order: explicit `mailbox` → the sole connected mailbox →
|
|
135
|
+
a typed refusal listing the connected mailboxes when two or more are attached and
|
|
136
|
+
none is named. Each resolution logs `cred-resolve account=<id> mailbox=<id>
|
|
137
|
+
source=arg|sole|none|refused`, so a wrong or absent selector is diagnosable from
|
|
138
|
+
one line. `outlook-mailbox-list` enumerates every mailbox on the account from the
|
|
139
|
+
local stores (no network) and flags any whose blob cannot be read.
|
|
140
|
+
|
|
113
141
|
## Refresh
|
|
114
142
|
|
|
115
143
|
Triggered automatically when the access token is within `5 minutes` of expiry (`refreshThresholdMs`). Failure → terminal `token-refresh-failed`, tokens cleared, operator must re-register. Refresh tokens last 90 days.
|
|
@@ -6,7 +6,21 @@ Microsoft Graph endpoints used by each tool, with the response shape and the fie
|
|
|
6
6
|
|
|
7
7
|
**Endpoint (Inbox):** `GET /me/mailFolders/Inbox/messages?$top={N}&$orderby=receivedDateTime DESC&$select=id,subject,from,receivedDateTime,bodyPreview,isRead`
|
|
8
8
|
|
|
9
|
-
**Endpoint (other folder):** `GET /me/mailFolders/{
|
|
9
|
+
**Endpoint (other folder):** `GET /me/mailFolders/{well-known-token-or-folderId}/messages?...`
|
|
10
|
+
|
|
11
|
+
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
|
+
|
|
13
|
+
| Input (any case/spacing) | Graph token |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `Inbox`, `` (empty) | `Inbox` |
|
|
16
|
+
| `Sent Items`, `sent` | `sentitems` |
|
|
17
|
+
| `Drafts` | `drafts` |
|
|
18
|
+
| `Deleted Items`, `trash` | `deleteditems` |
|
|
19
|
+
| `Junk Email`, `junk`, `spam` | `junkemail` |
|
|
20
|
+
| `Archive` | `archive` |
|
|
21
|
+
| `Outbox` | `outbox` |
|
|
22
|
+
|
|
23
|
+
Any value not in this table is treated as a raw folder id and passed through unchanged. A custom folder's display name (e.g. "Projects") is therefore not resolved — resolving custom folders by name would need a `/me/mailFolders` lookup and is out of scope.
|
|
10
24
|
|
|
11
25
|
**Returned shape:**
|
|
12
26
|
```typescript
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatcher script: publish-availability
|
|
3
|
+
*
|
|
4
|
+
* Self-contained, like reconcile-bookings. Publishes the install account's
|
|
5
|
+
* computed free/busy into its Cloudflare D1 `availability_snapshot` table so the
|
|
6
|
+
* public booking page's edge Function keeps serving open times while the device
|
|
7
|
+
* is offline. Runs while the device is ONLINE; when the device is off it simply
|
|
8
|
+
* does not run and the edge keeps serving the last snapshot until it returns.
|
|
9
|
+
*
|
|
10
|
+
* It reads the device's own free/busy from the always-running local server
|
|
11
|
+
* (127.0.0.1:$MAXY_UI_INTERNAL_PORT/api/calendar/free-busy — a gate-exempt public
|
|
12
|
+
* path), so it needs no Neo4j and no tunnel/DNS. The account whose free/busy the
|
|
13
|
+
* endpoint serves is the one the server resolved and hands in via
|
|
14
|
+
* PUBLISH_ACCOUNT_DIR / PUBLISH_ACCOUNT_ID.
|
|
15
|
+
*
|
|
16
|
+
* If the local endpoint is unreachable it makes NO D1 write (result=skipped-
|
|
17
|
+
* unreachable), leaving the last edge snapshot intact. A PID lock prevents
|
|
18
|
+
* overlapping runs. Each run records the outcome to a local last-publish.json so
|
|
19
|
+
* the server's audit tick can report snapshot age independent of this job.
|
|
20
|
+
*
|
|
21
|
+
* Observability — one [calendar-availability] op=publish line per run.
|
|
22
|
+
*
|
|
23
|
+
* PLATFORM_ROOT=... MAXY_UI_INTERNAL_PORT=... PUBLISH_ACCOUNT_DIR=... \
|
|
24
|
+
* PUBLISH_ACCOUNT_ID=... node dist/scripts/publish-availability.js
|
|
25
|
+
*/
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=publish-availability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-availability.d.ts","sourceRoot":"","sources":["../../src/scripts/publish-availability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|