@camstack/addon-google-services 0.1.4 → 0.1.5
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 +120 -55
- package/dist/google-services.addon.mjs +117 -56
- package/dist/index.js +4 -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,67 @@ 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
|
+
*/
|
|
53136
|
+
function redirectUriDisplay(publicOrigin) {
|
|
53137
|
+
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
53138
|
+
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
53139
|
+
}
|
|
53140
|
+
function introHtml(cap, publicOrigin) {
|
|
53141
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53142
|
+
if (cap === "smtp-provider") return [
|
|
53143
|
+
"<ol>",
|
|
53144
|
+
"<li>In Google Cloud Console enable the <b>Gmail API</b> (and Calendar API if you also use Calendars).</li>",
|
|
53145
|
+
"<li>Create an OAuth client of type <b>Web application</b>.</li>",
|
|
53146
|
+
`<li>Add this authorized redirect URI (Network → <b>Public endpoint</b>, not Internal): <code>${redirect}</code></li>`,
|
|
53147
|
+
"<li>Paste Client ID and Client secret below, then <b>Save</b>.</li>",
|
|
53148
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53149
|
+
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <b>Enable</b> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
53150
|
+
"</ol>"
|
|
53151
|
+
].join("");
|
|
53152
|
+
if (cap === "calendar-source") return [
|
|
53153
|
+
"<ol>",
|
|
53154
|
+
"<li>In Google Cloud Console enable the <b>Google Calendar API</b> (and Gmail API if you also use Email).</li>",
|
|
53155
|
+
"<li>Create an OAuth client of type <b>Web application</b>.</li>",
|
|
53156
|
+
`<li>Add this authorized redirect URI (Network → <b>Public endpoint</b>, not Internal): <code>${redirect}</code></li>`,
|
|
53157
|
+
"<li>Paste Client ID and Client secret below, then <b>Save</b>.</li>",
|
|
53158
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53159
|
+
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
53160
|
+
"</ol>"
|
|
53161
|
+
].join("");
|
|
53162
|
+
return [
|
|
53163
|
+
"<ol>",
|
|
53164
|
+
"<li>Enable <b>Google Calendar API</b> and <b>Gmail API</b> in Google Cloud Console.</li>",
|
|
53165
|
+
"<li>Create a <b>Web application</b> OAuth client.</li>",
|
|
53166
|
+
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
53167
|
+
"<li>Paste Client ID / secret, Save, then <a href=\"" + OAUTH_START_PATH + "\">Connect Google</a>.</li>",
|
|
53168
|
+
"<li>Calendars and Email share one Google account; use each page’s <b>Enable</b> toggle to turn a capability off without revoking OAuth.</li>",
|
|
53169
|
+
"</ol>"
|
|
53170
|
+
].join("");
|
|
53171
|
+
}
|
|
53172
|
+
function connectHtml(cap, publicOrigin) {
|
|
53173
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53174
|
+
if (cap === "smtp-provider") return [
|
|
53175
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53176
|
+
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
53177
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53178
|
+
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again."
|
|
53179
|
+
].join("");
|
|
53180
|
+
if (cap === "calendar-source") return [
|
|
53181
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53182
|
+
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
53183
|
+
`Google must list exactly: <code>${redirect}</code>.`
|
|
53184
|
+
].join("");
|
|
53185
|
+
return [`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `, `Redirect URI registered in Google Cloud must be <code>${redirect}</code>.`].join("");
|
|
53186
|
+
}
|
|
53187
|
+
function escapeHtml$1(s) {
|
|
53188
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53189
|
+
}
|
|
53190
|
+
//#endregion
|
|
53141
53191
|
//#region src/oauth-redirect-origin.ts
|
|
53142
53192
|
/**
|
|
53143
53193
|
* Google OAuth redirect origin — same role as hub OAuth2 / sign-in
|
|
@@ -53167,12 +53217,15 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53167
53217
|
oauth = { ...DEFAULT_OAUTH_STATE };
|
|
53168
53218
|
/** CSRF state → issuedAt ms */
|
|
53169
53219
|
pendingStates = /* @__PURE__ */ new Map();
|
|
53220
|
+
/** Cached Public-endpoint origin for settings copy (redirect URI display). */
|
|
53221
|
+
publicOrigin = null;
|
|
53170
53222
|
constructor() {
|
|
53171
53223
|
super({ ...DEFAULT_GOOGLE_CONFIG });
|
|
53172
53224
|
}
|
|
53173
53225
|
async onInitialize() {
|
|
53174
53226
|
this.oauthHandle = this.state("oauth", OauthStateSchema, { ...DEFAULT_OAUTH_STATE });
|
|
53175
53227
|
this.oauth = await this.oauthHandle.get();
|
|
53228
|
+
await this.refreshPublicOrigin();
|
|
53176
53229
|
const api = createGoogleCalendarApi(async () => this.ensureAccessToken());
|
|
53177
53230
|
const calendarProvider = createGoogleCalendarSource({
|
|
53178
53231
|
logger: this.ctx.logger,
|
|
@@ -53203,7 +53256,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53203
53256
|
this.ctx.logger.info("Initialized — google calendar-source + gmail smtp", { meta: {
|
|
53204
53257
|
connected: this.oauth.refreshToken.length > 0,
|
|
53205
53258
|
accountEmail: this.oauth.accountEmail || void 0,
|
|
53206
|
-
|
|
53259
|
+
publicOrigin: this.publicOrigin ?? void 0
|
|
53207
53260
|
} });
|
|
53208
53261
|
return { providers: [
|
|
53209
53262
|
{
|
|
@@ -53320,9 +53373,17 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53320
53373
|
return new Set(raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0));
|
|
53321
53374
|
}
|
|
53322
53375
|
async resolveRedirectUri() {
|
|
53323
|
-
|
|
53324
|
-
if (!
|
|
53325
|
-
return `${
|
|
53376
|
+
await this.refreshPublicOrigin();
|
|
53377
|
+
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).");
|
|
53378
|
+
return `${this.publicOrigin.replace(/\/$/, "")}/addon/${ADDON_ID}${CALLBACK_PATH}`;
|
|
53379
|
+
}
|
|
53380
|
+
async refreshPublicOrigin() {
|
|
53381
|
+
try {
|
|
53382
|
+
const book = await this.ctx.api.localNetwork.getAddresses.query({});
|
|
53383
|
+
this.publicOrigin = pickOauthRedirectOrigin(book);
|
|
53384
|
+
} catch {
|
|
53385
|
+
this.publicOrigin = null;
|
|
53386
|
+
}
|
|
53326
53387
|
}
|
|
53327
53388
|
/**
|
|
53328
53389
|
* Connectivity asks for settings scoped to the page capability, so Calendar
|
|
@@ -53330,23 +53391,25 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53330
53391
|
* mqtt-broker under `broker`). The addon page (no cap) keeps every section.
|
|
53331
53392
|
*/
|
|
53332
53393
|
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() {
|
|
53394
|
+
const scoped = asSettingsCap(cap);
|
|
53345
53395
|
return this.schema({ sections: [
|
|
53396
|
+
{
|
|
53397
|
+
id: "setup-intro",
|
|
53398
|
+
title: "Setup",
|
|
53399
|
+
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.",
|
|
53400
|
+
columns: 1,
|
|
53401
|
+
fields: [{
|
|
53402
|
+
type: "info",
|
|
53403
|
+
key: "_setupSteps",
|
|
53404
|
+
label: "Steps",
|
|
53405
|
+
format: "html",
|
|
53406
|
+
content: introHtml(scoped, this.publicOrigin)
|
|
53407
|
+
}]
|
|
53408
|
+
},
|
|
53346
53409
|
{
|
|
53347
53410
|
id: "google-oauth",
|
|
53348
53411
|
title: "Google account",
|
|
53349
|
-
description: "
|
|
53412
|
+
description: "OAuth client credentials (Web application) stored in the hub keychain.",
|
|
53350
53413
|
columns: 1,
|
|
53351
53414
|
fields: [
|
|
53352
53415
|
{
|
|
@@ -53365,11 +53428,11 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53365
53428
|
key: "_connectInfo",
|
|
53366
53429
|
label: "Connect",
|
|
53367
53430
|
format: "html",
|
|
53368
|
-
content:
|
|
53431
|
+
content: connectHtml(scoped, this.publicOrigin)
|
|
53369
53432
|
}
|
|
53370
53433
|
]
|
|
53371
53434
|
},
|
|
53372
|
-
{
|
|
53435
|
+
...scoped === "smtp-provider" ? [] : [{
|
|
53373
53436
|
id: "google-calendar",
|
|
53374
53437
|
title: "Google Calendar",
|
|
53375
53438
|
description: "Which calendars this hub exposes as calendar-source entries.",
|
|
@@ -53380,35 +53443,33 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53380
53443
|
label: "Calendar id filter (optional)",
|
|
53381
53444
|
description: "Comma-separated Google calendar ids to expose. Empty = all calendars the account can read."
|
|
53382
53445
|
}]
|
|
53383
|
-
},
|
|
53384
|
-
{
|
|
53446
|
+
}],
|
|
53447
|
+
...scoped === "calendar-source" ? [] : [{
|
|
53385
53448
|
id: "gmail-send",
|
|
53386
53449
|
title: "Gmail send",
|
|
53387
|
-
description: "
|
|
53450
|
+
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
53451
|
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
|
-
}
|
|
53452
|
+
fields: [{
|
|
53453
|
+
type: "text",
|
|
53454
|
+
key: "fromAddress",
|
|
53455
|
+
label: "From address",
|
|
53456
|
+
description: "Defaults to the connected Google account email when empty."
|
|
53457
|
+
}, {
|
|
53458
|
+
type: "text",
|
|
53459
|
+
key: "fromName",
|
|
53460
|
+
label: "From display name (optional)"
|
|
53461
|
+
}]
|
|
53462
|
+
}]
|
|
53409
53463
|
] });
|
|
53410
53464
|
}
|
|
53465
|
+
async getGlobalSettings(overlay, cap, nodeId) {
|
|
53466
|
+
await this.refreshPublicOrigin();
|
|
53467
|
+
return super.getGlobalSettings(overlay, cap, nodeId);
|
|
53468
|
+
}
|
|
53411
53469
|
};
|
|
53470
|
+
function asSettingsCap(cap) {
|
|
53471
|
+
if (cap === "calendar-source" || cap === "smtp-provider") return cap;
|
|
53472
|
+
}
|
|
53412
53473
|
function escapeHtml(s) {
|
|
53413
53474
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53414
53475
|
}
|
|
@@ -53419,13 +53480,17 @@ exports.GOOGLE_OAUTH_SCOPES = GOOGLE_OAUTH_SCOPES;
|
|
|
53419
53480
|
exports.GoogleServicesAddon = GoogleServicesAddon;
|
|
53420
53481
|
exports.default = GoogleServicesAddon;
|
|
53421
53482
|
exports.GoogleServicesConfigSchema = GoogleServicesConfigSchema;
|
|
53483
|
+
exports.OAUTH_START_PATH = OAUTH_START_PATH;
|
|
53422
53484
|
exports.applyTokenResponse = applyTokenResponse;
|
|
53423
53485
|
exports.buildAuthorizeUrl = buildAuthorizeUrl;
|
|
53424
53486
|
exports.buildRawMime = buildRawMime;
|
|
53487
|
+
exports.connectHtml = connectHtml;
|
|
53425
53488
|
exports.createGmailSmtpProvider = createGmailSmtpProvider;
|
|
53426
53489
|
exports.createGoogleCalendarApi = createGoogleCalendarApi;
|
|
53427
53490
|
exports.createGoogleCalendarSource = createGoogleCalendarSource;
|
|
53428
53491
|
exports.exchangeCode = exchangeCode;
|
|
53492
|
+
exports.introHtml = introHtml;
|
|
53429
53493
|
exports.mapGoogleEvent = mapGoogleEvent;
|
|
53430
53494
|
exports.needsRefresh = needsRefresh;
|
|
53495
|
+
exports.redirectUriDisplay = redirectUriDisplay;
|
|
53431
53496
|
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,67 @@ 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
|
+
*/
|
|
53132
|
+
function redirectUriDisplay(publicOrigin) {
|
|
53133
|
+
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
53134
|
+
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
53135
|
+
}
|
|
53136
|
+
function introHtml(cap, publicOrigin) {
|
|
53137
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53138
|
+
if (cap === "smtp-provider") return [
|
|
53139
|
+
"<ol>",
|
|
53140
|
+
"<li>In Google Cloud Console enable the <b>Gmail API</b> (and Calendar API if you also use Calendars).</li>",
|
|
53141
|
+
"<li>Create an OAuth client of type <b>Web application</b>.</li>",
|
|
53142
|
+
`<li>Add this authorized redirect URI (Network → <b>Public endpoint</b>, not Internal): <code>${redirect}</code></li>`,
|
|
53143
|
+
"<li>Paste Client ID and Client secret below, then <b>Save</b>.</li>",
|
|
53144
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53145
|
+
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <b>Enable</b> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
53146
|
+
"</ol>"
|
|
53147
|
+
].join("");
|
|
53148
|
+
if (cap === "calendar-source") return [
|
|
53149
|
+
"<ol>",
|
|
53150
|
+
"<li>In Google Cloud Console enable the <b>Google Calendar API</b> (and Gmail API if you also use Email).</li>",
|
|
53151
|
+
"<li>Create an OAuth client of type <b>Web application</b>.</li>",
|
|
53152
|
+
`<li>Add this authorized redirect URI (Network → <b>Public endpoint</b>, not Internal): <code>${redirect}</code></li>`,
|
|
53153
|
+
"<li>Paste Client ID and Client secret below, then <b>Save</b>.</li>",
|
|
53154
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
53155
|
+
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
53156
|
+
"</ol>"
|
|
53157
|
+
].join("");
|
|
53158
|
+
return [
|
|
53159
|
+
"<ol>",
|
|
53160
|
+
"<li>Enable <b>Google Calendar API</b> and <b>Gmail API</b> in Google Cloud Console.</li>",
|
|
53161
|
+
"<li>Create a <b>Web application</b> OAuth client.</li>",
|
|
53162
|
+
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
53163
|
+
"<li>Paste Client ID / secret, Save, then <a href=\"" + OAUTH_START_PATH + "\">Connect Google</a>.</li>",
|
|
53164
|
+
"<li>Calendars and Email share one Google account; use each page’s <b>Enable</b> toggle to turn a capability off without revoking OAuth.</li>",
|
|
53165
|
+
"</ol>"
|
|
53166
|
+
].join("");
|
|
53167
|
+
}
|
|
53168
|
+
function connectHtml(cap, publicOrigin) {
|
|
53169
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
53170
|
+
if (cap === "smtp-provider") return [
|
|
53171
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53172
|
+
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
53173
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
53174
|
+
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again."
|
|
53175
|
+
].join("");
|
|
53176
|
+
if (cap === "calendar-source") return [
|
|
53177
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
53178
|
+
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
53179
|
+
`Google must list exactly: <code>${redirect}</code>.`
|
|
53180
|
+
].join("");
|
|
53181
|
+
return [`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `, `Redirect URI registered in Google Cloud must be <code>${redirect}</code>.`].join("");
|
|
53182
|
+
}
|
|
53183
|
+
function escapeHtml$1(s) {
|
|
53184
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53185
|
+
}
|
|
53186
|
+
//#endregion
|
|
53137
53187
|
//#region src/oauth-redirect-origin.ts
|
|
53138
53188
|
/**
|
|
53139
53189
|
* Google OAuth redirect origin — same role as hub OAuth2 / sign-in
|
|
@@ -53163,12 +53213,15 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53163
53213
|
oauth = { ...DEFAULT_OAUTH_STATE };
|
|
53164
53214
|
/** CSRF state → issuedAt ms */
|
|
53165
53215
|
pendingStates = /* @__PURE__ */ new Map();
|
|
53216
|
+
/** Cached Public-endpoint origin for settings copy (redirect URI display). */
|
|
53217
|
+
publicOrigin = null;
|
|
53166
53218
|
constructor() {
|
|
53167
53219
|
super({ ...DEFAULT_GOOGLE_CONFIG });
|
|
53168
53220
|
}
|
|
53169
53221
|
async onInitialize() {
|
|
53170
53222
|
this.oauthHandle = this.state("oauth", OauthStateSchema, { ...DEFAULT_OAUTH_STATE });
|
|
53171
53223
|
this.oauth = await this.oauthHandle.get();
|
|
53224
|
+
await this.refreshPublicOrigin();
|
|
53172
53225
|
const api = createGoogleCalendarApi(async () => this.ensureAccessToken());
|
|
53173
53226
|
const calendarProvider = createGoogleCalendarSource({
|
|
53174
53227
|
logger: this.ctx.logger,
|
|
@@ -53199,7 +53252,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53199
53252
|
this.ctx.logger.info("Initialized — google calendar-source + gmail smtp", { meta: {
|
|
53200
53253
|
connected: this.oauth.refreshToken.length > 0,
|
|
53201
53254
|
accountEmail: this.oauth.accountEmail || void 0,
|
|
53202
|
-
|
|
53255
|
+
publicOrigin: this.publicOrigin ?? void 0
|
|
53203
53256
|
} });
|
|
53204
53257
|
return { providers: [
|
|
53205
53258
|
{
|
|
@@ -53316,9 +53369,17 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53316
53369
|
return new Set(raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0));
|
|
53317
53370
|
}
|
|
53318
53371
|
async resolveRedirectUri() {
|
|
53319
|
-
|
|
53320
|
-
if (!
|
|
53321
|
-
return `${
|
|
53372
|
+
await this.refreshPublicOrigin();
|
|
53373
|
+
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).");
|
|
53374
|
+
return `${this.publicOrigin.replace(/\/$/, "")}/addon/${ADDON_ID}${CALLBACK_PATH}`;
|
|
53375
|
+
}
|
|
53376
|
+
async refreshPublicOrigin() {
|
|
53377
|
+
try {
|
|
53378
|
+
const book = await this.ctx.api.localNetwork.getAddresses.query({});
|
|
53379
|
+
this.publicOrigin = pickOauthRedirectOrigin(book);
|
|
53380
|
+
} catch {
|
|
53381
|
+
this.publicOrigin = null;
|
|
53382
|
+
}
|
|
53322
53383
|
}
|
|
53323
53384
|
/**
|
|
53324
53385
|
* Connectivity asks for settings scoped to the page capability, so Calendar
|
|
@@ -53326,23 +53387,25 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53326
53387
|
* mqtt-broker under `broker`). The addon page (no cap) keeps every section.
|
|
53327
53388
|
*/
|
|
53328
53389
|
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() {
|
|
53390
|
+
const scoped = asSettingsCap(cap);
|
|
53341
53391
|
return this.schema({ sections: [
|
|
53392
|
+
{
|
|
53393
|
+
id: "setup-intro",
|
|
53394
|
+
title: "Setup",
|
|
53395
|
+
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.",
|
|
53396
|
+
columns: 1,
|
|
53397
|
+
fields: [{
|
|
53398
|
+
type: "info",
|
|
53399
|
+
key: "_setupSteps",
|
|
53400
|
+
label: "Steps",
|
|
53401
|
+
format: "html",
|
|
53402
|
+
content: introHtml(scoped, this.publicOrigin)
|
|
53403
|
+
}]
|
|
53404
|
+
},
|
|
53342
53405
|
{
|
|
53343
53406
|
id: "google-oauth",
|
|
53344
53407
|
title: "Google account",
|
|
53345
|
-
description: "
|
|
53408
|
+
description: "OAuth client credentials (Web application) stored in the hub keychain.",
|
|
53346
53409
|
columns: 1,
|
|
53347
53410
|
fields: [
|
|
53348
53411
|
{
|
|
@@ -53361,11 +53424,11 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53361
53424
|
key: "_connectInfo",
|
|
53362
53425
|
label: "Connect",
|
|
53363
53426
|
format: "html",
|
|
53364
|
-
content:
|
|
53427
|
+
content: connectHtml(scoped, this.publicOrigin)
|
|
53365
53428
|
}
|
|
53366
53429
|
]
|
|
53367
53430
|
},
|
|
53368
|
-
{
|
|
53431
|
+
...scoped === "smtp-provider" ? [] : [{
|
|
53369
53432
|
id: "google-calendar",
|
|
53370
53433
|
title: "Google Calendar",
|
|
53371
53434
|
description: "Which calendars this hub exposes as calendar-source entries.",
|
|
@@ -53376,37 +53439,35 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
53376
53439
|
label: "Calendar id filter (optional)",
|
|
53377
53440
|
description: "Comma-separated Google calendar ids to expose. Empty = all calendars the account can read."
|
|
53378
53441
|
}]
|
|
53379
|
-
},
|
|
53380
|
-
{
|
|
53442
|
+
}],
|
|
53443
|
+
...scoped === "calendar-source" ? [] : [{
|
|
53381
53444
|
id: "gmail-send",
|
|
53382
53445
|
title: "Gmail send",
|
|
53383
|
-
description: "
|
|
53446
|
+
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
53447
|
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
|
-
}
|
|
53448
|
+
fields: [{
|
|
53449
|
+
type: "text",
|
|
53450
|
+
key: "fromAddress",
|
|
53451
|
+
label: "From address",
|
|
53452
|
+
description: "Defaults to the connected Google account email when empty."
|
|
53453
|
+
}, {
|
|
53454
|
+
type: "text",
|
|
53455
|
+
key: "fromName",
|
|
53456
|
+
label: "From display name (optional)"
|
|
53457
|
+
}]
|
|
53458
|
+
}]
|
|
53405
53459
|
] });
|
|
53406
53460
|
}
|
|
53461
|
+
async getGlobalSettings(overlay, cap, nodeId) {
|
|
53462
|
+
await this.refreshPublicOrigin();
|
|
53463
|
+
return super.getGlobalSettings(overlay, cap, nodeId);
|
|
53464
|
+
}
|
|
53407
53465
|
};
|
|
53466
|
+
function asSettingsCap(cap) {
|
|
53467
|
+
if (cap === "calendar-source" || cap === "smtp-provider") return cap;
|
|
53468
|
+
}
|
|
53408
53469
|
function escapeHtml(s) {
|
|
53409
53470
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
53410
53471
|
}
|
|
53411
53472
|
//#endregion
|
|
53412
|
-
export { GoogleServicesAddon, GoogleServicesAddon as default,
|
|
53473
|
+
export { GoogleServicesAddon, GoogleServicesAddon as default, GoogleServicesConfigSchema as _, buildAuthorizeUrl as a, refreshAccessToken as c, createGoogleCalendarApi as d, createGoogleCalendarSource as f, GOOGLE_OAUTH_SCOPES as g, GOOGLE_GMAIL_SEND_SCOPE as h, applyTokenResponse as i, buildRawMime as l, DEFAULT_GOOGLE_CONFIG as m, introHtml as n, exchangeCode as o, mapGoogleEvent as p, redirectUriDisplay as r, needsRefresh as s, connectHtml as t, createGmailSmtpProvider as u, OAUTH_START_PATH as v };
|
package/dist/index.js
CHANGED
|
@@ -8,14 +8,18 @@ exports.GOOGLE_GMAIL_SEND_SCOPE = require_google_services_addon.GOOGLE_GMAIL_SEN
|
|
|
8
8
|
exports.GOOGLE_OAUTH_SCOPES = require_google_services_addon.GOOGLE_OAUTH_SCOPES;
|
|
9
9
|
exports.GoogleServicesAddon = require_google_services_addon.GoogleServicesAddon;
|
|
10
10
|
exports.GoogleServicesConfigSchema = require_google_services_addon.GoogleServicesConfigSchema;
|
|
11
|
+
exports.OAUTH_START_PATH = require_google_services_addon.OAUTH_START_PATH;
|
|
11
12
|
exports.applyTokenResponse = require_google_services_addon.applyTokenResponse;
|
|
12
13
|
exports.buildAuthorizeUrl = require_google_services_addon.buildAuthorizeUrl;
|
|
13
14
|
exports.buildRawMime = require_google_services_addon.buildRawMime;
|
|
15
|
+
exports.connectHtml = require_google_services_addon.connectHtml;
|
|
14
16
|
exports.createGmailSmtpProvider = require_google_services_addon.createGmailSmtpProvider;
|
|
15
17
|
exports.createGoogleCalendarApi = require_google_services_addon.createGoogleCalendarApi;
|
|
16
18
|
exports.createGoogleCalendarSource = require_google_services_addon.createGoogleCalendarSource;
|
|
17
19
|
exports.default = require_google_services_addon.GoogleServicesAddon;
|
|
18
20
|
exports.exchangeCode = require_google_services_addon.exchangeCode;
|
|
21
|
+
exports.introHtml = require_google_services_addon.introHtml;
|
|
19
22
|
exports.mapGoogleEvent = require_google_services_addon.mapGoogleEvent;
|
|
20
23
|
exports.needsRefresh = require_google_services_addon.needsRefresh;
|
|
24
|
+
exports.redirectUriDisplay = require_google_services_addon.redirectUriDisplay;
|
|
21
25
|
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 GoogleServicesConfigSchema, a as buildAuthorizeUrl, c as refreshAccessToken, d as createGoogleCalendarApi, f as createGoogleCalendarSource, g as GOOGLE_OAUTH_SCOPES, h as GOOGLE_GMAIL_SEND_SCOPE, i as applyTokenResponse, l as buildRawMime, m as DEFAULT_GOOGLE_CONFIG, n as introHtml, o as exchangeCode, p as mapGoogleEvent, r as redirectUriDisplay, s as needsRefresh, t as connectHtml, u as createGmailSmtpProvider, v as OAUTH_START_PATH } from "./google-services.addon.mjs";
|
|
2
|
+
export { DEFAULT_GOOGLE_CONFIG, 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