@camstack/addon-google-services 0.1.4 → 0.1.6
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/google-services.addon.js +141 -55
- package/dist/google-services.addon.mjs +136 -56
- package/dist/index.js +6 -0
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -52805,8 +52805,6 @@ var GoogleServicesConfigSchema = object({
|
|
|
52805
52805
|
clientSecret: string().default("").meta({ secret: true }),
|
|
52806
52806
|
/** Comma-separated Google calendar ids to expose; empty = all. */
|
|
52807
52807
|
calendarFilter: string().default(""),
|
|
52808
|
-
/** Offer Gmail send via `smtp-provider` (same OAuth account). */
|
|
52809
|
-
gmailSendEnabled: boolean().default(false),
|
|
52810
52808
|
/** Default From for Gmail send — usually the connected account email. */
|
|
52811
52809
|
fromAddress: string().default(""),
|
|
52812
52810
|
fromName: string().default("")
|
|
@@ -52827,6 +52825,8 @@ var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
|
52827
52825
|
var GOOGLE_CALENDAR_API = "https://www.googleapis.com/calendar/v3";
|
|
52828
52826
|
var GOOGLE_GMAIL_API = "https://gmail.googleapis.com/gmail/v1";
|
|
52829
52827
|
var GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo";
|
|
52828
|
+
var OAUTH_START_PATH = `/addon/google-services/oauth/start`;
|
|
52829
|
+
var OAUTH_CALLBACK_SUFFIX = `/addon/google-services/oauth/callback`;
|
|
52830
52830
|
//#endregion
|
|
52831
52831
|
//#region src/google-calendar-source.ts
|
|
52832
52832
|
function parseGoogleInstant(value) {
|
|
@@ -52984,12 +52984,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
52984
52984
|
const status = () => {
|
|
52985
52985
|
const cfg = deps.getConfig();
|
|
52986
52986
|
const email = deps.getAccountEmail() || cfg.fromAddress.trim() || "gmail";
|
|
52987
|
-
if (!cfg.gmailSendEnabled) return {
|
|
52988
|
-
ready: false,
|
|
52989
|
-
host: email,
|
|
52990
|
-
error: "Gmail send is disabled in Google Services settings.",
|
|
52991
|
-
lastVerifiedAt
|
|
52992
|
-
};
|
|
52993
52987
|
if (!deps.connected()) return {
|
|
52994
52988
|
ready: false,
|
|
52995
52989
|
host: email,
|
|
@@ -53006,10 +53000,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
53006
53000
|
return {
|
|
53007
53001
|
getStatus: async () => status(),
|
|
53008
53002
|
verify: async () => {
|
|
53009
|
-
if (!deps.getConfig().gmailSendEnabled) {
|
|
53010
|
-
lastError = "Gmail send is disabled in Google Services settings.";
|
|
53011
|
-
return status();
|
|
53012
|
-
}
|
|
53013
53003
|
if (!deps.connected()) {
|
|
53014
53004
|
lastError = "Google account is not connected.";
|
|
53015
53005
|
return status();
|
|
@@ -53032,7 +53022,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
53032
53022
|
},
|
|
53033
53023
|
sendEmail: async (input) => {
|
|
53034
53024
|
const cfg = deps.getConfig();
|
|
53035
|
-
if (!cfg.gmailSendEnabled) throw new Error("Gmail send is disabled in Google Services settings.");
|
|
53036
53025
|
if (!deps.connected()) throw new Error("Google account is not connected — open Connect Google.");
|
|
53037
53026
|
const from = input.from?.trim() || buildFromHeader(cfg, deps.getAccountEmail());
|
|
53038
53027
|
if (!from) throw new Error("Set From address in Google Services settings (or connect an account).");
|
|
@@ -53138,6 +53127,86 @@ function needsRefresh(state, nowMs = Date.now()) {
|
|
|
53138
53127
|
return state.accessExpiresAt <= nowMs;
|
|
53139
53128
|
}
|
|
53140
53129
|
//#endregion
|
|
53130
|
+
//#region src/google-settings-copy.ts
|
|
53131
|
+
/**
|
|
53132
|
+
* Operator-facing setup copy for Connectivity → Calendars / Email.
|
|
53133
|
+
* Keep Connect as a same-origin relative link so the admin session cookie
|
|
53134
|
+
* rides along (an absolute Public URL from a LAN admin tab drops the cookie).
|
|
53135
|
+
* Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
|
|
53136
|
+
*/
|
|
53137
|
+
/** Enable APIs library in Google Cloud Console. */
|
|
53138
|
+
var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
|
|
53139
|
+
/** Create / manage OAuth Web clients. */
|
|
53140
|
+
var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
|
|
53141
|
+
function redirectUriDisplay(publicOrigin) {
|
|
53142
|
+
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
53143
|
+
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
53144
|
+
}
|
|
53145
|
+
function consoleLinksHtml() {
|
|
53146
|
+
return [
|
|
53147
|
+
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
53148
|
+
` · `,
|
|
53149
|
+
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
53150
|
+
].join("");
|
|
53151
|
+
}
|
|
53152
|
+
function introHtml(cap, publicOrigin) {
|
|
53153
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53154
|
+
const console = consoleLinksHtml();
|
|
53155
|
+
if (cap === "smtp-provider") return [
|
|
53156
|
+
"<ol>",
|
|
53157
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
|
|
53158
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
53159
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
53160
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
53161
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53162
|
+
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
53163
|
+
"</ol>"
|
|
53164
|
+
].join("");
|
|
53165
|
+
if (cap === "calendar-source") return [
|
|
53166
|
+
"<ol>",
|
|
53167
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
|
|
53168
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
53169
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
53170
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
53171
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53172
|
+
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
53173
|
+
"</ol>"
|
|
53174
|
+
].join("");
|
|
53175
|
+
return [
|
|
53176
|
+
"<ol>",
|
|
53177
|
+
`<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
|
|
53178
|
+
"<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
|
|
53179
|
+
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
53180
|
+
`<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
|
|
53181
|
+
"<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
|
|
53182
|
+
"</ol>"
|
|
53183
|
+
].join("");
|
|
53184
|
+
}
|
|
53185
|
+
function connectHtml(cap, publicOrigin) {
|
|
53186
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53187
|
+
if (cap === "smtp-provider") return [
|
|
53188
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53189
|
+
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
53190
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53191
|
+
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
|
|
53192
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53193
|
+
].join("");
|
|
53194
|
+
if (cap === "calendar-source") return [
|
|
53195
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53196
|
+
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
53197
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53198
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53199
|
+
].join("");
|
|
53200
|
+
return [
|
|
53201
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
|
|
53202
|
+
`Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
|
|
53203
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53204
|
+
].join("");
|
|
53205
|
+
}
|
|
53206
|
+
function escapeHtml$1(s) {
|
|
53207
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53208
|
+
}
|
|
53209
|
+
//#endregion
|
|
53141
53210
|
//#region src/oauth-redirect-origin.ts
|
|
53142
53211
|
/**
|
|
53143
53212
|
* Google OAuth redirect origin — same role as hub OAuth2 / sign-in
|
|
@@ -53167,12 +53236,15 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53167
53236
|
oauth = { ...DEFAULT_OAUTH_STATE };
|
|
53168
53237
|
/** CSRF state → issuedAt ms */
|
|
53169
53238
|
pendingStates = /* @__PURE__ */ new Map();
|
|
53239
|
+
/** Cached Public-endpoint origin for settings copy (redirect URI display). */
|
|
53240
|
+
publicOrigin = null;
|
|
53170
53241
|
constructor() {
|
|
53171
53242
|
super({ ...DEFAULT_GOOGLE_CONFIG });
|
|
53172
53243
|
}
|
|
53173
53244
|
async onInitialize() {
|
|
53174
53245
|
this.oauthHandle = this.state("oauth", OauthStateSchema, { ...DEFAULT_OAUTH_STATE });
|
|
53175
53246
|
this.oauth = await this.oauthHandle.get();
|
|
53247
|
+
await this.refreshPublicOrigin();
|
|
53176
53248
|
const api = createGoogleCalendarApi(async () => this.ensureAccessToken());
|
|
53177
53249
|
const calendarProvider = createGoogleCalendarSource({
|
|
53178
53250
|
logger: this.ctx.logger,
|
|
@@ -53203,7 +53275,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53203
53275
|
this.ctx.logger.info("Initialized — google calendar-source + gmail smtp", { meta: {
|
|
53204
53276
|
connected: this.oauth.refreshToken.length > 0,
|
|
53205
53277
|
accountEmail: this.oauth.accountEmail || void 0,
|
|
53206
|
-
|
|
53278
|
+
publicOrigin: this.publicOrigin ?? void 0
|
|
53207
53279
|
} });
|
|
53208
53280
|
return { providers: [
|
|
53209
53281
|
{
|
|
@@ -53320,9 +53392,17 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53320
53392
|
return new Set(raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0));
|
|
53321
53393
|
}
|
|
53322
53394
|
async resolveRedirectUri() {
|
|
53323
|
-
|
|
53324
|
-
if (!
|
|
53325
|
-
return `${
|
|
53395
|
+
await this.refreshPublicOrigin();
|
|
53396
|
+
if (!this.publicOrigin) throw new Error("No hub public address available from local-network — set a Public endpoint on the Network page (OAuth2 redirects use that role, not Internal).");
|
|
53397
|
+
return `${this.publicOrigin.replace(/\/$/, "")}/addon/${ADDON_ID}${CALLBACK_PATH}`;
|
|
53398
|
+
}
|
|
53399
|
+
async refreshPublicOrigin() {
|
|
53400
|
+
try {
|
|
53401
|
+
const book = await this.ctx.api.localNetwork.getAddresses.query({});
|
|
53402
|
+
this.publicOrigin = pickOauthRedirectOrigin(book);
|
|
53403
|
+
} catch {
|
|
53404
|
+
this.publicOrigin = null;
|
|
53405
|
+
}
|
|
53326
53406
|
}
|
|
53327
53407
|
/**
|
|
53328
53408
|
* Connectivity asks for settings scoped to the page capability, so Calendar
|
|
@@ -53330,23 +53410,25 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53330
53410
|
* mqtt-broker under `broker`). The addon page (no cap) keeps every section.
|
|
53331
53411
|
*/
|
|
53332
53412
|
globalSettingsSchema(cap) {
|
|
53333
|
-
const
|
|
53334
|
-
if (cap === "calendar-source") return {
|
|
53335
|
-
...schema,
|
|
53336
|
-
sections: schema.sections.filter((s) => s.id === "google-oauth" || s.id === "google-calendar")
|
|
53337
|
-
};
|
|
53338
|
-
if (cap === "smtp-provider") return {
|
|
53339
|
-
...schema,
|
|
53340
|
-
sections: schema.sections.filter((s) => s.id === "google-oauth" || s.id === "gmail-send")
|
|
53341
|
-
};
|
|
53342
|
-
return schema;
|
|
53343
|
-
}
|
|
53344
|
-
fullSettingsSchema() {
|
|
53413
|
+
const scoped = asSettingsCap(cap);
|
|
53345
53414
|
return this.schema({ sections: [
|
|
53415
|
+
{
|
|
53416
|
+
id: "setup-intro",
|
|
53417
|
+
title: "Setup",
|
|
53418
|
+
description: scoped === "smtp-provider" ? "Connect a Google account for Gmail send (same OAuth as Calendars)." : scoped === "calendar-source" ? "Connect a Google account for Calendar (same OAuth as Email)." : "One Google account for Calendar and optional Gmail send.",
|
|
53419
|
+
columns: 1,
|
|
53420
|
+
fields: [{
|
|
53421
|
+
type: "info",
|
|
53422
|
+
key: "_setupSteps",
|
|
53423
|
+
label: "Steps",
|
|
53424
|
+
format: "html",
|
|
53425
|
+
content: introHtml(scoped, this.publicOrigin)
|
|
53426
|
+
}]
|
|
53427
|
+
},
|
|
53346
53428
|
{
|
|
53347
53429
|
id: "google-oauth",
|
|
53348
53430
|
title: "Google account",
|
|
53349
|
-
description: "
|
|
53431
|
+
description: "OAuth client credentials (Web application) stored in the hub keychain.",
|
|
53350
53432
|
columns: 1,
|
|
53351
53433
|
fields: [
|
|
53352
53434
|
{
|
|
@@ -53365,11 +53447,11 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53365
53447
|
key: "_connectInfo",
|
|
53366
53448
|
label: "Connect",
|
|
53367
53449
|
format: "html",
|
|
53368
|
-
content:
|
|
53450
|
+
content: connectHtml(scoped, this.publicOrigin)
|
|
53369
53451
|
}
|
|
53370
53452
|
]
|
|
53371
53453
|
},
|
|
53372
|
-
{
|
|
53454
|
+
...scoped === "smtp-provider" ? [] : [{
|
|
53373
53455
|
id: "google-calendar",
|
|
53374
53456
|
title: "Google Calendar",
|
|
53375
53457
|
description: "Which calendars this hub exposes as calendar-source entries.",
|
|
@@ -53380,52 +53462,56 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53380
53462
|
label: "Calendar id filter (optional)",
|
|
53381
53463
|
description: "Comma-separated Google calendar ids to expose. Empty = all calendars the account can read."
|
|
53382
53464
|
}]
|
|
53383
|
-
},
|
|
53384
|
-
{
|
|
53465
|
+
}],
|
|
53466
|
+
...scoped === "calendar-source" ? [] : [{
|
|
53385
53467
|
id: "gmail-send",
|
|
53386
53468
|
title: "Gmail send",
|
|
53387
|
-
description: "
|
|
53469
|
+
description: "Delivery via the Gmail API. Disable this capability with the page Enable toggle — not a second switch here. From must be the connected account or a verified send-as.",
|
|
53388
53470
|
columns: 1,
|
|
53389
|
-
fields: [
|
|
53390
|
-
|
|
53391
|
-
|
|
53392
|
-
|
|
53393
|
-
|
|
53394
|
-
|
|
53395
|
-
|
|
53396
|
-
|
|
53397
|
-
|
|
53398
|
-
|
|
53399
|
-
|
|
53400
|
-
description: "Defaults to the connected Google account email when empty."
|
|
53401
|
-
},
|
|
53402
|
-
{
|
|
53403
|
-
type: "text",
|
|
53404
|
-
key: "fromName",
|
|
53405
|
-
label: "From display name (optional)"
|
|
53406
|
-
}
|
|
53407
|
-
]
|
|
53408
|
-
}
|
|
53471
|
+
fields: [{
|
|
53472
|
+
type: "text",
|
|
53473
|
+
key: "fromAddress",
|
|
53474
|
+
label: "From address",
|
|
53475
|
+
description: "Defaults to the connected Google account email when empty."
|
|
53476
|
+
}, {
|
|
53477
|
+
type: "text",
|
|
53478
|
+
key: "fromName",
|
|
53479
|
+
label: "From display name (optional)"
|
|
53480
|
+
}]
|
|
53481
|
+
}]
|
|
53409
53482
|
] });
|
|
53410
53483
|
}
|
|
53484
|
+
async getGlobalSettings(overlay, cap, nodeId) {
|
|
53485
|
+
await this.refreshPublicOrigin();
|
|
53486
|
+
return super.getGlobalSettings(overlay, cap, nodeId);
|
|
53487
|
+
}
|
|
53411
53488
|
};
|
|
53489
|
+
function asSettingsCap(cap) {
|
|
53490
|
+
if (cap === "calendar-source" || cap === "smtp-provider") return cap;
|
|
53491
|
+
}
|
|
53412
53492
|
function escapeHtml(s) {
|
|
53413
53493
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53414
53494
|
}
|
|
53415
53495
|
//#endregion
|
|
53416
53496
|
exports.DEFAULT_GOOGLE_CONFIG = DEFAULT_GOOGLE_CONFIG;
|
|
53497
|
+
exports.GOOGLE_CONSOLE_APIS_URL = GOOGLE_CONSOLE_APIS_URL;
|
|
53498
|
+
exports.GOOGLE_CONSOLE_CREDENTIALS_URL = GOOGLE_CONSOLE_CREDENTIALS_URL;
|
|
53417
53499
|
exports.GOOGLE_GMAIL_SEND_SCOPE = GOOGLE_GMAIL_SEND_SCOPE;
|
|
53418
53500
|
exports.GOOGLE_OAUTH_SCOPES = GOOGLE_OAUTH_SCOPES;
|
|
53419
53501
|
exports.GoogleServicesAddon = GoogleServicesAddon;
|
|
53420
53502
|
exports.default = GoogleServicesAddon;
|
|
53421
53503
|
exports.GoogleServicesConfigSchema = GoogleServicesConfigSchema;
|
|
53504
|
+
exports.OAUTH_START_PATH = OAUTH_START_PATH;
|
|
53422
53505
|
exports.applyTokenResponse = applyTokenResponse;
|
|
53423
53506
|
exports.buildAuthorizeUrl = buildAuthorizeUrl;
|
|
53424
53507
|
exports.buildRawMime = buildRawMime;
|
|
53508
|
+
exports.connectHtml = connectHtml;
|
|
53425
53509
|
exports.createGmailSmtpProvider = createGmailSmtpProvider;
|
|
53426
53510
|
exports.createGoogleCalendarApi = createGoogleCalendarApi;
|
|
53427
53511
|
exports.createGoogleCalendarSource = createGoogleCalendarSource;
|
|
53428
53512
|
exports.exchangeCode = exchangeCode;
|
|
53513
|
+
exports.introHtml = introHtml;
|
|
53429
53514
|
exports.mapGoogleEvent = mapGoogleEvent;
|
|
53430
53515
|
exports.needsRefresh = needsRefresh;
|
|
53516
|
+
exports.redirectUriDisplay = redirectUriDisplay;
|
|
53431
53517
|
exports.refreshAccessToken = refreshAccessToken;
|
|
@@ -52801,8 +52801,6 @@ var GoogleServicesConfigSchema = object({
|
|
|
52801
52801
|
clientSecret: string().default("").meta({ secret: true }),
|
|
52802
52802
|
/** Comma-separated Google calendar ids to expose; empty = all. */
|
|
52803
52803
|
calendarFilter: string().default(""),
|
|
52804
|
-
/** Offer Gmail send via `smtp-provider` (same OAuth account). */
|
|
52805
|
-
gmailSendEnabled: boolean().default(false),
|
|
52806
52804
|
/** Default From for Gmail send — usually the connected account email. */
|
|
52807
52805
|
fromAddress: string().default(""),
|
|
52808
52806
|
fromName: string().default("")
|
|
@@ -52823,6 +52821,8 @@ var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
|
52823
52821
|
var GOOGLE_CALENDAR_API = "https://www.googleapis.com/calendar/v3";
|
|
52824
52822
|
var GOOGLE_GMAIL_API = "https://gmail.googleapis.com/gmail/v1";
|
|
52825
52823
|
var GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo";
|
|
52824
|
+
var OAUTH_START_PATH = `/addon/google-services/oauth/start`;
|
|
52825
|
+
var OAUTH_CALLBACK_SUFFIX = `/addon/google-services/oauth/callback`;
|
|
52826
52826
|
//#endregion
|
|
52827
52827
|
//#region src/google-calendar-source.ts
|
|
52828
52828
|
function parseGoogleInstant(value) {
|
|
@@ -52980,12 +52980,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
52980
52980
|
const status = () => {
|
|
52981
52981
|
const cfg = deps.getConfig();
|
|
52982
52982
|
const email = deps.getAccountEmail() || cfg.fromAddress.trim() || "gmail";
|
|
52983
|
-
if (!cfg.gmailSendEnabled) return {
|
|
52984
|
-
ready: false,
|
|
52985
|
-
host: email,
|
|
52986
|
-
error: "Gmail send is disabled in Google Services settings.",
|
|
52987
|
-
lastVerifiedAt
|
|
52988
|
-
};
|
|
52989
52983
|
if (!deps.connected()) return {
|
|
52990
52984
|
ready: false,
|
|
52991
52985
|
host: email,
|
|
@@ -53002,10 +52996,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
53002
52996
|
return {
|
|
53003
52997
|
getStatus: async () => status(),
|
|
53004
52998
|
verify: async () => {
|
|
53005
|
-
if (!deps.getConfig().gmailSendEnabled) {
|
|
53006
|
-
lastError = "Gmail send is disabled in Google Services settings.";
|
|
53007
|
-
return status();
|
|
53008
|
-
}
|
|
53009
52999
|
if (!deps.connected()) {
|
|
53010
53000
|
lastError = "Google account is not connected.";
|
|
53011
53001
|
return status();
|
|
@@ -53028,7 +53018,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
53028
53018
|
},
|
|
53029
53019
|
sendEmail: async (input) => {
|
|
53030
53020
|
const cfg = deps.getConfig();
|
|
53031
|
-
if (!cfg.gmailSendEnabled) throw new Error("Gmail send is disabled in Google Services settings.");
|
|
53032
53021
|
if (!deps.connected()) throw new Error("Google account is not connected — open Connect Google.");
|
|
53033
53022
|
const from = input.from?.trim() || buildFromHeader(cfg, deps.getAccountEmail());
|
|
53034
53023
|
if (!from) throw new Error("Set From address in Google Services settings (or connect an account).");
|
|
@@ -53134,6 +53123,86 @@ function needsRefresh(state, nowMs = Date.now()) {
|
|
|
53134
53123
|
return state.accessExpiresAt <= nowMs;
|
|
53135
53124
|
}
|
|
53136
53125
|
//#endregion
|
|
53126
|
+
//#region src/google-settings-copy.ts
|
|
53127
|
+
/**
|
|
53128
|
+
* Operator-facing setup copy for Connectivity → Calendars / Email.
|
|
53129
|
+
* Keep Connect as a same-origin relative link so the admin session cookie
|
|
53130
|
+
* rides along (an absolute Public URL from a LAN admin tab drops the cookie).
|
|
53131
|
+
* Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
|
|
53132
|
+
*/
|
|
53133
|
+
/** Enable APIs library in Google Cloud Console. */
|
|
53134
|
+
var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
|
|
53135
|
+
/** Create / manage OAuth Web clients. */
|
|
53136
|
+
var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
|
|
53137
|
+
function redirectUriDisplay(publicOrigin) {
|
|
53138
|
+
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
53139
|
+
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
53140
|
+
}
|
|
53141
|
+
function consoleLinksHtml() {
|
|
53142
|
+
return [
|
|
53143
|
+
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
53144
|
+
` · `,
|
|
53145
|
+
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
53146
|
+
].join("");
|
|
53147
|
+
}
|
|
53148
|
+
function introHtml(cap, publicOrigin) {
|
|
53149
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53150
|
+
const console = consoleLinksHtml();
|
|
53151
|
+
if (cap === "smtp-provider") return [
|
|
53152
|
+
"<ol>",
|
|
53153
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
|
|
53154
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
53155
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
53156
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
53157
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53158
|
+
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
53159
|
+
"</ol>"
|
|
53160
|
+
].join("");
|
|
53161
|
+
if (cap === "calendar-source") return [
|
|
53162
|
+
"<ol>",
|
|
53163
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
|
|
53164
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
53165
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
53166
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
53167
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53168
|
+
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
53169
|
+
"</ol>"
|
|
53170
|
+
].join("");
|
|
53171
|
+
return [
|
|
53172
|
+
"<ol>",
|
|
53173
|
+
`<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
|
|
53174
|
+
"<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
|
|
53175
|
+
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
53176
|
+
`<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
|
|
53177
|
+
"<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
|
|
53178
|
+
"</ol>"
|
|
53179
|
+
].join("");
|
|
53180
|
+
}
|
|
53181
|
+
function connectHtml(cap, publicOrigin) {
|
|
53182
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53183
|
+
if (cap === "smtp-provider") return [
|
|
53184
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53185
|
+
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
53186
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53187
|
+
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
|
|
53188
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53189
|
+
].join("");
|
|
53190
|
+
if (cap === "calendar-source") return [
|
|
53191
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53192
|
+
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
53193
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53194
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53195
|
+
].join("");
|
|
53196
|
+
return [
|
|
53197
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
|
|
53198
|
+
`Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
|
|
53199
|
+
`Console: ${consoleLinksHtml()}.`
|
|
53200
|
+
].join("");
|
|
53201
|
+
}
|
|
53202
|
+
function escapeHtml$1(s) {
|
|
53203
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53204
|
+
}
|
|
53205
|
+
//#endregion
|
|
53137
53206
|
//#region src/oauth-redirect-origin.ts
|
|
53138
53207
|
/**
|
|
53139
53208
|
* Google OAuth redirect origin — same role as hub OAuth2 / sign-in
|
|
@@ -53163,12 +53232,15 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53163
53232
|
oauth = { ...DEFAULT_OAUTH_STATE };
|
|
53164
53233
|
/** CSRF state → issuedAt ms */
|
|
53165
53234
|
pendingStates = /* @__PURE__ */ new Map();
|
|
53235
|
+
/** Cached Public-endpoint origin for settings copy (redirect URI display). */
|
|
53236
|
+
publicOrigin = null;
|
|
53166
53237
|
constructor() {
|
|
53167
53238
|
super({ ...DEFAULT_GOOGLE_CONFIG });
|
|
53168
53239
|
}
|
|
53169
53240
|
async onInitialize() {
|
|
53170
53241
|
this.oauthHandle = this.state("oauth", OauthStateSchema, { ...DEFAULT_OAUTH_STATE });
|
|
53171
53242
|
this.oauth = await this.oauthHandle.get();
|
|
53243
|
+
await this.refreshPublicOrigin();
|
|
53172
53244
|
const api = createGoogleCalendarApi(async () => this.ensureAccessToken());
|
|
53173
53245
|
const calendarProvider = createGoogleCalendarSource({
|
|
53174
53246
|
logger: this.ctx.logger,
|
|
@@ -53199,7 +53271,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53199
53271
|
this.ctx.logger.info("Initialized — google calendar-source + gmail smtp", { meta: {
|
|
53200
53272
|
connected: this.oauth.refreshToken.length > 0,
|
|
53201
53273
|
accountEmail: this.oauth.accountEmail || void 0,
|
|
53202
|
-
|
|
53274
|
+
publicOrigin: this.publicOrigin ?? void 0
|
|
53203
53275
|
} });
|
|
53204
53276
|
return { providers: [
|
|
53205
53277
|
{
|
|
@@ -53316,9 +53388,17 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53316
53388
|
return new Set(raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0));
|
|
53317
53389
|
}
|
|
53318
53390
|
async resolveRedirectUri() {
|
|
53319
|
-
|
|
53320
|
-
if (!
|
|
53321
|
-
return `${
|
|
53391
|
+
await this.refreshPublicOrigin();
|
|
53392
|
+
if (!this.publicOrigin) throw new Error("No hub public address available from local-network — set a Public endpoint on the Network page (OAuth2 redirects use that role, not Internal).");
|
|
53393
|
+
return `${this.publicOrigin.replace(/\/$/, "")}/addon/${ADDON_ID}${CALLBACK_PATH}`;
|
|
53394
|
+
}
|
|
53395
|
+
async refreshPublicOrigin() {
|
|
53396
|
+
try {
|
|
53397
|
+
const book = await this.ctx.api.localNetwork.getAddresses.query({});
|
|
53398
|
+
this.publicOrigin = pickOauthRedirectOrigin(book);
|
|
53399
|
+
} catch {
|
|
53400
|
+
this.publicOrigin = null;
|
|
53401
|
+
}
|
|
53322
53402
|
}
|
|
53323
53403
|
/**
|
|
53324
53404
|
* Connectivity asks for settings scoped to the page capability, so Calendar
|
|
@@ -53326,23 +53406,25 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53326
53406
|
* mqtt-broker under `broker`). The addon page (no cap) keeps every section.
|
|
53327
53407
|
*/
|
|
53328
53408
|
globalSettingsSchema(cap) {
|
|
53329
|
-
const
|
|
53330
|
-
if (cap === "calendar-source") return {
|
|
53331
|
-
...schema,
|
|
53332
|
-
sections: schema.sections.filter((s) => s.id === "google-oauth" || s.id === "google-calendar")
|
|
53333
|
-
};
|
|
53334
|
-
if (cap === "smtp-provider") return {
|
|
53335
|
-
...schema,
|
|
53336
|
-
sections: schema.sections.filter((s) => s.id === "google-oauth" || s.id === "gmail-send")
|
|
53337
|
-
};
|
|
53338
|
-
return schema;
|
|
53339
|
-
}
|
|
53340
|
-
fullSettingsSchema() {
|
|
53409
|
+
const scoped = asSettingsCap(cap);
|
|
53341
53410
|
return this.schema({ sections: [
|
|
53411
|
+
{
|
|
53412
|
+
id: "setup-intro",
|
|
53413
|
+
title: "Setup",
|
|
53414
|
+
description: scoped === "smtp-provider" ? "Connect a Google account for Gmail send (same OAuth as Calendars)." : scoped === "calendar-source" ? "Connect a Google account for Calendar (same OAuth as Email)." : "One Google account for Calendar and optional Gmail send.",
|
|
53415
|
+
columns: 1,
|
|
53416
|
+
fields: [{
|
|
53417
|
+
type: "info",
|
|
53418
|
+
key: "_setupSteps",
|
|
53419
|
+
label: "Steps",
|
|
53420
|
+
format: "html",
|
|
53421
|
+
content: introHtml(scoped, this.publicOrigin)
|
|
53422
|
+
}]
|
|
53423
|
+
},
|
|
53342
53424
|
{
|
|
53343
53425
|
id: "google-oauth",
|
|
53344
53426
|
title: "Google account",
|
|
53345
|
-
description: "
|
|
53427
|
+
description: "OAuth client credentials (Web application) stored in the hub keychain.",
|
|
53346
53428
|
columns: 1,
|
|
53347
53429
|
fields: [
|
|
53348
53430
|
{
|
|
@@ -53361,11 +53443,11 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53361
53443
|
key: "_connectInfo",
|
|
53362
53444
|
label: "Connect",
|
|
53363
53445
|
format: "html",
|
|
53364
|
-
content:
|
|
53446
|
+
content: connectHtml(scoped, this.publicOrigin)
|
|
53365
53447
|
}
|
|
53366
53448
|
]
|
|
53367
53449
|
},
|
|
53368
|
-
{
|
|
53450
|
+
...scoped === "smtp-provider" ? [] : [{
|
|
53369
53451
|
id: "google-calendar",
|
|
53370
53452
|
title: "Google Calendar",
|
|
53371
53453
|
description: "Which calendars this hub exposes as calendar-source entries.",
|
|
@@ -53376,37 +53458,35 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53376
53458
|
label: "Calendar id filter (optional)",
|
|
53377
53459
|
description: "Comma-separated Google calendar ids to expose. Empty = all calendars the account can read."
|
|
53378
53460
|
}]
|
|
53379
|
-
},
|
|
53380
|
-
{
|
|
53461
|
+
}],
|
|
53462
|
+
...scoped === "calendar-source" ? [] : [{
|
|
53381
53463
|
id: "gmail-send",
|
|
53382
53464
|
title: "Gmail send",
|
|
53383
|
-
description: "
|
|
53465
|
+
description: "Delivery via the Gmail API. Disable this capability with the page Enable toggle — not a second switch here. From must be the connected account or a verified send-as.",
|
|
53384
53466
|
columns: 1,
|
|
53385
|
-
fields: [
|
|
53386
|
-
|
|
53387
|
-
|
|
53388
|
-
|
|
53389
|
-
|
|
53390
|
-
|
|
53391
|
-
|
|
53392
|
-
|
|
53393
|
-
|
|
53394
|
-
|
|
53395
|
-
|
|
53396
|
-
description: "Defaults to the connected Google account email when empty."
|
|
53397
|
-
},
|
|
53398
|
-
{
|
|
53399
|
-
type: "text",
|
|
53400
|
-
key: "fromName",
|
|
53401
|
-
label: "From display name (optional)"
|
|
53402
|
-
}
|
|
53403
|
-
]
|
|
53404
|
-
}
|
|
53467
|
+
fields: [{
|
|
53468
|
+
type: "text",
|
|
53469
|
+
key: "fromAddress",
|
|
53470
|
+
label: "From address",
|
|
53471
|
+
description: "Defaults to the connected Google account email when empty."
|
|
53472
|
+
}, {
|
|
53473
|
+
type: "text",
|
|
53474
|
+
key: "fromName",
|
|
53475
|
+
label: "From display name (optional)"
|
|
53476
|
+
}]
|
|
53477
|
+
}]
|
|
53405
53478
|
] });
|
|
53406
53479
|
}
|
|
53480
|
+
async getGlobalSettings(overlay, cap, nodeId) {
|
|
53481
|
+
await this.refreshPublicOrigin();
|
|
53482
|
+
return super.getGlobalSettings(overlay, cap, nodeId);
|
|
53483
|
+
}
|
|
53407
53484
|
};
|
|
53485
|
+
function asSettingsCap(cap) {
|
|
53486
|
+
if (cap === "calendar-source" || cap === "smtp-provider") return cap;
|
|
53487
|
+
}
|
|
53408
53488
|
function escapeHtml(s) {
|
|
53409
53489
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53410
53490
|
}
|
|
53411
53491
|
//#endregion
|
|
53412
|
-
export { GoogleServicesAddon, GoogleServicesAddon as default,
|
|
53492
|
+
export { GoogleServicesAddon, GoogleServicesAddon as default, GOOGLE_GMAIL_SEND_SCOPE as _, redirectUriDisplay as a, OAUTH_START_PATH as b, exchangeCode as c, buildRawMime as d, createGmailSmtpProvider as f, DEFAULT_GOOGLE_CONFIG as g, mapGoogleEvent as h, introHtml as i, needsRefresh as l, createGoogleCalendarSource as m, GOOGLE_CONSOLE_CREDENTIALS_URL as n, applyTokenResponse as o, createGoogleCalendarApi as p, connectHtml as r, buildAuthorizeUrl as s, GOOGLE_CONSOLE_APIS_URL as t, refreshAccessToken as u, GOOGLE_OAUTH_SCOPES as v, GoogleServicesConfigSchema as y };
|
package/dist/index.js
CHANGED
|
@@ -4,18 +4,24 @@ Object.defineProperties(exports, {
|
|
|
4
4
|
});
|
|
5
5
|
const require_google_services_addon = require("./google-services.addon.js");
|
|
6
6
|
exports.DEFAULT_GOOGLE_CONFIG = require_google_services_addon.DEFAULT_GOOGLE_CONFIG;
|
|
7
|
+
exports.GOOGLE_CONSOLE_APIS_URL = require_google_services_addon.GOOGLE_CONSOLE_APIS_URL;
|
|
8
|
+
exports.GOOGLE_CONSOLE_CREDENTIALS_URL = require_google_services_addon.GOOGLE_CONSOLE_CREDENTIALS_URL;
|
|
7
9
|
exports.GOOGLE_GMAIL_SEND_SCOPE = require_google_services_addon.GOOGLE_GMAIL_SEND_SCOPE;
|
|
8
10
|
exports.GOOGLE_OAUTH_SCOPES = require_google_services_addon.GOOGLE_OAUTH_SCOPES;
|
|
9
11
|
exports.GoogleServicesAddon = require_google_services_addon.GoogleServicesAddon;
|
|
10
12
|
exports.GoogleServicesConfigSchema = require_google_services_addon.GoogleServicesConfigSchema;
|
|
13
|
+
exports.OAUTH_START_PATH = require_google_services_addon.OAUTH_START_PATH;
|
|
11
14
|
exports.applyTokenResponse = require_google_services_addon.applyTokenResponse;
|
|
12
15
|
exports.buildAuthorizeUrl = require_google_services_addon.buildAuthorizeUrl;
|
|
13
16
|
exports.buildRawMime = require_google_services_addon.buildRawMime;
|
|
17
|
+
exports.connectHtml = require_google_services_addon.connectHtml;
|
|
14
18
|
exports.createGmailSmtpProvider = require_google_services_addon.createGmailSmtpProvider;
|
|
15
19
|
exports.createGoogleCalendarApi = require_google_services_addon.createGoogleCalendarApi;
|
|
16
20
|
exports.createGoogleCalendarSource = require_google_services_addon.createGoogleCalendarSource;
|
|
17
21
|
exports.default = require_google_services_addon.GoogleServicesAddon;
|
|
18
22
|
exports.exchangeCode = require_google_services_addon.exchangeCode;
|
|
23
|
+
exports.introHtml = require_google_services_addon.introHtml;
|
|
19
24
|
exports.mapGoogleEvent = require_google_services_addon.mapGoogleEvent;
|
|
20
25
|
exports.needsRefresh = require_google_services_addon.needsRefresh;
|
|
26
|
+
exports.redirectUriDisplay = require_google_services_addon.redirectUriDisplay;
|
|
21
27
|
exports.refreshAccessToken = require_google_services_addon.refreshAccessToken;
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GoogleServicesAddon, a as
|
|
2
|
-
export { DEFAULT_GOOGLE_CONFIG, GOOGLE_GMAIL_SEND_SCOPE, GOOGLE_OAUTH_SCOPES, GoogleServicesAddon, GoogleServicesAddon as default, GoogleServicesConfigSchema, applyTokenResponse, buildAuthorizeUrl, buildRawMime, createGmailSmtpProvider, createGoogleCalendarApi, createGoogleCalendarSource, exchangeCode, mapGoogleEvent, needsRefresh, refreshAccessToken };
|
|
1
|
+
import { GoogleServicesAddon, _ as GOOGLE_GMAIL_SEND_SCOPE, a as redirectUriDisplay, b as OAUTH_START_PATH, c as exchangeCode, d as buildRawMime, f as createGmailSmtpProvider, g as DEFAULT_GOOGLE_CONFIG, h as mapGoogleEvent, i as introHtml, l as needsRefresh, m as createGoogleCalendarSource, n as GOOGLE_CONSOLE_CREDENTIALS_URL, o as applyTokenResponse, p as createGoogleCalendarApi, r as connectHtml, s as buildAuthorizeUrl, t as GOOGLE_CONSOLE_APIS_URL, u as refreshAccessToken, v as GOOGLE_OAUTH_SCOPES, y as GoogleServicesConfigSchema } from "./google-services.addon.mjs";
|
|
2
|
+
export { DEFAULT_GOOGLE_CONFIG, GOOGLE_CONSOLE_APIS_URL, GOOGLE_CONSOLE_CREDENTIALS_URL, GOOGLE_GMAIL_SEND_SCOPE, GOOGLE_OAUTH_SCOPES, GoogleServicesAddon, GoogleServicesAddon as default, GoogleServicesConfigSchema, OAUTH_START_PATH, applyTokenResponse, buildAuthorizeUrl, buildRawMime, connectHtml, createGmailSmtpProvider, createGoogleCalendarApi, createGoogleCalendarSource, exchangeCode, introHtml, mapGoogleEvent, needsRefresh, redirectUriDisplay, refreshAccessToken };
|
package/package.json
CHANGED