@camstack/addon-google-services 0.2.45 → 0.2.46
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/CHANGELOG.md +8 -0
- package/dist/google-services.addon.js +75 -138
- package/dist/google-services.addon.mjs +75 -138
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.46] - 2026-11-09
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Gmail send provider drops the unused verify call
|
|
15
|
+
|
|
10
16
|
## [0.2.45] - 2026-11-09
|
|
11
17
|
|
|
12
18
|
### Fixed
|
|
13
19
|
|
|
14
20
|
- Each imported calendar names the record that owns it, so its switch is found on the Calendars page
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
15
23
|
|
|
16
24
|
## [0.2.44] - 2026-11-08
|
|
17
25
|
|
|
@@ -6016,7 +6016,7 @@ var ZodIssueCode = {
|
|
|
6016
6016
|
var ZodFirstPartyTypeKind;
|
|
6017
6017
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6018
6018
|
//#endregion
|
|
6019
|
-
//#region ../types/dist/sleep-
|
|
6019
|
+
//#region ../types/dist/sleep-CkinsFFb.mjs
|
|
6020
6020
|
/**
|
|
6021
6021
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6022
6022
|
* window to float samples (D455).
|
|
@@ -8695,16 +8695,6 @@ var BaseAddon = class {
|
|
|
8695
8695
|
return null;
|
|
8696
8696
|
}
|
|
8697
8697
|
/**
|
|
8698
|
-
* The form schema of ONE integration instance, or `null` to use the scoped form.
|
|
8699
|
-
*
|
|
8700
|
-
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
8701
|
-
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
8702
|
-
* SHAPE of the form only — the values live on the instance record.
|
|
8703
|
-
*/
|
|
8704
|
-
async integrationFormSchema(_instance) {
|
|
8705
|
-
return null;
|
|
8706
|
-
}
|
|
8707
|
-
/**
|
|
8708
8698
|
* D986 scoped settings: the form shape of the CLUSTER-wide settings one capability this addon
|
|
8709
8699
|
* provides owns, or `null` when it has none. `cap` is a capability name the addon's manifest
|
|
8710
8700
|
* declares. Stored as `addon-settings` rows `<addonId>.<field>`. The keys of this schema, of
|
|
@@ -8732,8 +8722,7 @@ var BaseAddon = class {
|
|
|
8732
8722
|
}
|
|
8733
8723
|
/**
|
|
8734
8724
|
* The host's read of the scoped declarations: the schema one capability declares for `scope`,
|
|
8735
|
-
* or `null`.
|
|
8736
|
-
* host asks this method.
|
|
8725
|
+
* or `null`. The hook is protected, the host asks this method.
|
|
8737
8726
|
*/
|
|
8738
8727
|
async getScopedSettingsSchema(scope, cap) {
|
|
8739
8728
|
switch (scope) {
|
|
@@ -8901,22 +8890,6 @@ var BaseAddon = class {
|
|
|
8901
8890
|
return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
|
|
8902
8891
|
}
|
|
8903
8892
|
/**
|
|
8904
|
-
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
8905
|
-
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8906
|
-
*/
|
|
8907
|
-
async getIntegrationFormSchema(instance, nodeId) {
|
|
8908
|
-
const scoped = await this.integrationFormSchema(instance);
|
|
8909
|
-
if (scoped === null) return this.scopedForm(nodeId);
|
|
8910
|
-
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8911
|
-
}
|
|
8912
|
-
/** The form of the scoped schemas this addon declared, hydrated from its store. */
|
|
8913
|
-
async scopedForm(nodeId) {
|
|
8914
|
-
await this.loadScopedSchemas();
|
|
8915
|
-
const schema = this.scopedFormSchema();
|
|
8916
|
-
if (!schema) return { sections: [] };
|
|
8917
|
-
return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
|
|
8918
|
-
}
|
|
8919
|
-
/**
|
|
8920
8893
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
8921
8894
|
* every `perNode: true` field carries THAT node's scoped value on its bare
|
|
8922
8895
|
* key (absent scoped key ⇒ key absent, so the schema `default` wins — no
|
|
@@ -9103,12 +9076,6 @@ var BaseAddon = class {
|
|
|
9103
9076
|
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
9104
9077
|
this._addonSecretTree = null;
|
|
9105
9078
|
}
|
|
9106
|
-
/** The form of an addon's scoped schemas: their sections, each shown once. */
|
|
9107
|
-
scopedFormSchema(cap) {
|
|
9108
|
-
const byId = /* @__PURE__ */ new Map();
|
|
9109
|
-
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
9110
|
-
return byId.size === 0 ? null : { sections: [...byId.values()] };
|
|
9111
|
-
}
|
|
9112
9079
|
/** Every loaded scoped schema of `cap`, or of every loaded capability. */
|
|
9113
9080
|
loadedScopedSchemas(cap) {
|
|
9114
9081
|
if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
|
|
@@ -9698,6 +9665,24 @@ function normalizeAddonInitResult(result) {
|
|
|
9698
9665
|
if (Array.isArray(result)) return { providers: result };
|
|
9699
9666
|
return result;
|
|
9700
9667
|
}
|
|
9668
|
+
object({
|
|
9669
|
+
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
9670
|
+
params: record(string(), union([string(), number$1()])).optional()
|
|
9671
|
+
});
|
|
9672
|
+
var CamstackError = class extends Error {
|
|
9673
|
+
i18nCode;
|
|
9674
|
+
i18nParams;
|
|
9675
|
+
constructor(code, params, englishMessage) {
|
|
9676
|
+
super(englishMessage);
|
|
9677
|
+
this.name = "CamstackError";
|
|
9678
|
+
this.i18nCode = code;
|
|
9679
|
+
this.i18nParams = params;
|
|
9680
|
+
}
|
|
9681
|
+
};
|
|
9682
|
+
/** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
|
|
9683
|
+
function userError(code, params, englishFallback) {
|
|
9684
|
+
return new CamstackError(code, params, englishFallback);
|
|
9685
|
+
}
|
|
9701
9686
|
object({
|
|
9702
9687
|
field: string().min(1),
|
|
9703
9688
|
on: literal("advance")
|
|
@@ -9774,12 +9759,6 @@ function systemMethod(input, output, options) {
|
|
|
9774
9759
|
systemOnly: true
|
|
9775
9760
|
};
|
|
9776
9761
|
}
|
|
9777
|
-
/**
|
|
9778
|
-
* A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
|
|
9779
|
-
* on `InferProvider`. The `providerOptional: true` literal is what
|
|
9780
|
-
* `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
|
|
9781
|
-
* for when this is the honest answer and when it is a soft stub.
|
|
9782
|
-
*/
|
|
9783
9762
|
function optionalMethod(input, output, options) {
|
|
9784
9763
|
return {
|
|
9785
9764
|
...method(input, output, options),
|
|
@@ -17174,24 +17153,6 @@ Object.freeze({
|
|
|
17174
17153
|
"uploadDataset": 72e5
|
|
17175
17154
|
}
|
|
17176
17155
|
});
|
|
17177
|
-
object({
|
|
17178
|
-
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
17179
|
-
params: record(string(), union([string(), number$1()])).optional()
|
|
17180
|
-
});
|
|
17181
|
-
var CamstackError = class extends Error {
|
|
17182
|
-
i18nCode;
|
|
17183
|
-
i18nParams;
|
|
17184
|
-
constructor(code, params, englishMessage) {
|
|
17185
|
-
super(englishMessage);
|
|
17186
|
-
this.name = "CamstackError";
|
|
17187
|
-
this.i18nCode = code;
|
|
17188
|
-
this.i18nParams = params;
|
|
17189
|
-
}
|
|
17190
|
-
};
|
|
17191
|
-
/** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
|
|
17192
|
-
function userError(code, params, englishFallback) {
|
|
17193
|
-
return new CamstackError(code, params, englishFallback);
|
|
17194
|
-
}
|
|
17195
17156
|
//#endregion
|
|
17196
17157
|
//#region ../types/dist/composition-CXCX78IR.mjs
|
|
17197
17158
|
/**
|
|
@@ -18903,25 +18864,6 @@ var RequiredAddonUpdateSchema = object({
|
|
|
18903
18864
|
installed: string().nullable()
|
|
18904
18865
|
});
|
|
18905
18866
|
/**
|
|
18906
|
-
* Which integration instance a settings form is for. An addon that serves several instances
|
|
18907
|
-
* (`instanceMode: multiple`) can show a different form per instance — an NVR integration
|
|
18908
|
-
* needs its connection, the default integration needs the addon's own sections.
|
|
18909
|
-
*
|
|
18910
|
-
* - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
|
|
18911
|
-
* setting up a NEW instance.
|
|
18912
|
-
* - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
|
|
18913
|
-
* - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
|
|
18914
|
-
*/
|
|
18915
|
-
var IntegrationInstanceRefSchema = object({
|
|
18916
|
-
integrationId: string().nullable(),
|
|
18917
|
-
mode: _enum([
|
|
18918
|
-
"standalone",
|
|
18919
|
-
"account",
|
|
18920
|
-
"broker"
|
|
18921
|
-
]),
|
|
18922
|
-
candidateStableId: string().optional()
|
|
18923
|
-
});
|
|
18924
|
-
/**
|
|
18925
18867
|
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
18926
18868
|
* both the operator-facing `getRoutes` (returning route descriptors
|
|
18927
18869
|
* minus the handlers, which can't cross JSON) and the framework-
|
|
@@ -19098,8 +19040,8 @@ function composeInstanceKinds(parts, base) {
|
|
|
19098
19040
|
instanceFormSchema: async ({ id, kind }) => {
|
|
19099
19041
|
return (id === null ? byKind(kind) : await holderOf(id)).provider.instanceFormSchema({ id });
|
|
19100
19042
|
},
|
|
19101
|
-
listInstances: async () => {
|
|
19102
|
-
return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances()).map((instance) => tagged(part, instance))))).flat();
|
|
19043
|
+
listInstances: async (input) => {
|
|
19044
|
+
return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances(input)).map((instance) => tagged(part, instance))))).flat();
|
|
19103
19045
|
},
|
|
19104
19046
|
getInstance: async ({ id }) => {
|
|
19105
19047
|
for (const part of parts) {
|
|
@@ -45244,10 +45186,6 @@ method(object({
|
|
|
45244
45186
|
scope: ScopedSettingsScopeSchema,
|
|
45245
45187
|
nodeId: string().optional()
|
|
45246
45188
|
}), record(string(), unknown()).nullable()), method(object({
|
|
45247
|
-
addonId: string(),
|
|
45248
|
-
nodeId: string().optional(),
|
|
45249
|
-
instance: IntegrationInstanceRefSchema
|
|
45250
|
-
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
45251
45189
|
addonId: string(),
|
|
45252
45190
|
nodeId: string().optional()
|
|
45253
45191
|
}), object({ keys: array(string()) }).nullable(), { auth: "admin" }), method(object({
|
|
@@ -55652,6 +55590,12 @@ var IntegrationWithStateSchema = object({
|
|
|
55652
55590
|
name: string(),
|
|
55653
55591
|
/** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
|
|
55654
55592
|
enabled: boolean(),
|
|
55593
|
+
/**
|
|
55594
|
+
* True when the addon that holds the switch did not answer (down, failed, or keeps no record for
|
|
55595
|
+
* this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
|
|
55596
|
+
* must not draw it as on or off (D315).
|
|
55597
|
+
*/
|
|
55598
|
+
switchUnknown: literal(true).optional(),
|
|
55655
55599
|
info: record(string(), unknown()).readonly(),
|
|
55656
55600
|
/** The discovery candidate this integration was set up from (D984). */
|
|
55657
55601
|
originStableId: string().optional(),
|
|
@@ -55665,6 +55609,12 @@ var IntegrationLiteSchema = object({
|
|
|
55665
55609
|
name: string(),
|
|
55666
55610
|
/** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
|
|
55667
55611
|
enabled: boolean(),
|
|
55612
|
+
/**
|
|
55613
|
+
* True when the addon that holds the switch did not answer (down, failed, or keeps no record for
|
|
55614
|
+
* this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
|
|
55615
|
+
* must not draw it as on or off (D315).
|
|
55616
|
+
*/
|
|
55617
|
+
switchUnknown: literal(true).optional(),
|
|
55668
55618
|
info: record(string(), unknown()).readonly(),
|
|
55669
55619
|
/** The discovery candidate this integration was set up from (D984). */
|
|
55670
55620
|
originStableId: string().optional(),
|
|
@@ -55763,9 +55713,9 @@ var UpdateIntegrationInputSchema = object({
|
|
|
55763
55713
|
id: string(),
|
|
55764
55714
|
name: string().optional(),
|
|
55765
55715
|
/**
|
|
55766
|
-
*
|
|
55767
|
-
*
|
|
55768
|
-
*
|
|
55716
|
+
* Honoured ONLY for a fixed builtin (`info.fixed`), whose switch is the hub's own registry flag
|
|
55717
|
+
* and works while its addon is down. Any other row is refused (a typed `BAD_REQUEST`): its
|
|
55718
|
+
* switch is `integration-instances.setInstanceEnabled`.
|
|
55769
55719
|
*/
|
|
55770
55720
|
enabled: boolean().optional(),
|
|
55771
55721
|
info: record(string(), unknown()).optional()
|
|
@@ -55799,6 +55749,12 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
55799
55749
|
* the form as a `SecretFieldView`, never text (D789). A patch value omitted, `''`
|
|
55800
55750
|
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
55801
55751
|
* clears it.
|
|
55752
|
+
*
|
|
55753
|
+
* Who may call (epic #440): every method but `describe` and `instanceFormSchema` is open to any
|
|
55754
|
+
* session (`caller: 'scoped'`) and default-denies. An admin passes everywhere. A non-admin passes
|
|
55755
|
+
* only on a call pinned to one addon whose `describe().userScoped` is true, and that provider
|
|
55756
|
+
* filters every row on the `caller` the router injected (a notification target is somebody's
|
|
55757
|
+
* phone: a user sees and changes only their own). An addon that says nothing keeps the admin door.
|
|
55802
55758
|
*/
|
|
55803
55759
|
var ConfigSchemaPassthrough$2 = custom();
|
|
55804
55760
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
@@ -55912,7 +55868,15 @@ var IntegrationInstanceDescriptionSchema = object({
|
|
|
55912
55868
|
*/
|
|
55913
55869
|
mintsId: boolean().optional(),
|
|
55914
55870
|
/** The links to other instances the provider's kinds declare; absent means none. */
|
|
55915
|
-
links: array(IntegrationInstanceLinkSchema).optional()
|
|
55871
|
+
links: array(IntegrationInstanceLinkSchema).optional(),
|
|
55872
|
+
/**
|
|
55873
|
+
* The rows belong to individual users (a notification target is somebody's phone). The router
|
|
55874
|
+
* then opens `listInstances`, `getInstance`, `createInstance`, `updateInstance`,
|
|
55875
|
+
* `setInstanceEnabled`, `deleteInstance` and `testInstance` to a NON-admin session on a call
|
|
55876
|
+
* pinned to this addon, and hands the provider the `caller` so it keeps a user to their own rows.
|
|
55877
|
+
* Absent means admin only, as it always was.
|
|
55878
|
+
*/
|
|
55879
|
+
userScoped: boolean().optional()
|
|
55916
55880
|
});
|
|
55917
55881
|
var IntegrationInstanceStatusSchema = object({
|
|
55918
55882
|
state: _enum([
|
|
@@ -55970,8 +55934,14 @@ var integrationInstancesCapability = {
|
|
|
55970
55934
|
/** The discovery candidate the wizard was seeded from (`stableId`), if any. */
|
|
55971
55935
|
candidateStableId: string().min(1).optional()
|
|
55972
55936
|
}), ConfigSchemaPassthrough$2, { auth: "admin" }),
|
|
55973
|
-
listInstances: method(
|
|
55974
|
-
|
|
55937
|
+
listInstances: method(looseObject({}), array(IntegrationInstanceSchema).readonly(), {
|
|
55938
|
+
auth: "protected",
|
|
55939
|
+
caller: "scoped"
|
|
55940
|
+
}),
|
|
55941
|
+
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), {
|
|
55942
|
+
auth: "protected",
|
|
55943
|
+
caller: "scoped"
|
|
55944
|
+
}),
|
|
55975
55945
|
/**
|
|
55976
55946
|
* Insert the typed record. With `id` it is stored under that id (a duplicate id is refused);
|
|
55977
55947
|
* without one the PROVIDER mints it and answers it. `kind` picks one of `describe().kinds`.
|
|
@@ -56004,11 +55974,13 @@ var integrationInstancesCapability = {
|
|
|
56004
55974
|
seed: object({ info: record(string(), unknown()) }).optional()
|
|
56005
55975
|
}), object({ id: string() }), {
|
|
56006
55976
|
kind: "mutation",
|
|
56007
|
-
auth: "
|
|
55977
|
+
auth: "protected",
|
|
55978
|
+
caller: "scoped"
|
|
56008
55979
|
}),
|
|
56009
55980
|
updateInstance: method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
56010
55981
|
kind: "mutation",
|
|
56011
|
-
auth: "
|
|
55982
|
+
auth: "protected",
|
|
55983
|
+
caller: "scoped"
|
|
56012
55984
|
}),
|
|
56013
55985
|
/**
|
|
56014
55986
|
* Switch ONE instance on or off, for every role; a missing record is created from the addon's
|
|
@@ -56020,7 +55992,8 @@ var integrationInstancesCapability = {
|
|
|
56020
55992
|
enabled: boolean()
|
|
56021
55993
|
}), object({ ok: literal(true) }), {
|
|
56022
55994
|
kind: "mutation",
|
|
56023
|
-
auth: "
|
|
55995
|
+
auth: "protected",
|
|
55996
|
+
caller: "scoped"
|
|
56024
55997
|
}),
|
|
56025
55998
|
/**
|
|
56026
55999
|
* Delete the record and its keychain refs together. For an instance that brings devices the hub
|
|
@@ -56029,7 +56002,8 @@ var integrationInstancesCapability = {
|
|
|
56029
56002
|
*/
|
|
56030
56003
|
deleteInstance: method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
56031
56004
|
kind: "mutation",
|
|
56032
|
-
auth: "
|
|
56005
|
+
auth: "protected",
|
|
56006
|
+
caller: "scoped"
|
|
56033
56007
|
}),
|
|
56034
56008
|
testInstance: optionalMethod(object({
|
|
56035
56009
|
id: IntegrationInstanceIdSchema.nullable(),
|
|
@@ -56038,7 +56012,8 @@ var integrationInstancesCapability = {
|
|
|
56038
56012
|
kind: string().min(1).optional()
|
|
56039
56013
|
}), TestConnectionResultSchema, {
|
|
56040
56014
|
kind: "mutation",
|
|
56041
|
-
auth: "
|
|
56015
|
+
auth: "protected",
|
|
56016
|
+
caller: "scoped"
|
|
56042
56017
|
})
|
|
56043
56018
|
}
|
|
56044
56019
|
};
|
|
@@ -73888,6 +73863,11 @@ var SendEmailResultSchema = object({
|
|
|
73888
73863
|
var SmtpStatusSchema = object({
|
|
73889
73864
|
/** True iff the addon has successfully verified the relay. */
|
|
73890
73865
|
ready: boolean(),
|
|
73866
|
+
/**
|
|
73867
|
+
* The tri-state behind `ready` (D315): true when the last send worked, false when it failed,
|
|
73868
|
+
* ABSENT when the relay has not sent yet (unknown, never "not verified").
|
|
73869
|
+
*/
|
|
73870
|
+
verified: boolean().optional(),
|
|
73891
73871
|
/** Operator-visible host string (no credentials). */
|
|
73892
73872
|
host: string(),
|
|
73893
73873
|
/** Last error message reported by the relay, when not ready. */
|
|
@@ -73907,13 +73887,6 @@ var smtpProviderCapability = {
|
|
|
73907
73887
|
auth: "admin",
|
|
73908
73888
|
access: "create"
|
|
73909
73889
|
}),
|
|
73910
|
-
/** Round-trip ping against the SMTP relay (EHLO + AUTH if configured).
|
|
73911
|
-
* Used by the operator's "Test connection" button. */
|
|
73912
|
-
verify: method(RelayPinSchema, SmtpStatusSchema, {
|
|
73913
|
-
kind: "mutation",
|
|
73914
|
-
auth: "admin",
|
|
73915
|
-
access: "view"
|
|
73916
|
-
}),
|
|
73917
73890
|
getStatus: method(RelayPinSchema, SmtpStatusSchema, { auth: "admin" })
|
|
73918
73891
|
}
|
|
73919
73892
|
};
|
|
@@ -80584,13 +80557,6 @@ Object.freeze({
|
|
|
80584
80557
|
access: "view",
|
|
80585
80558
|
role: "admin"
|
|
80586
80559
|
},
|
|
80587
|
-
"addonSettings.getIntegrationFormSchema": {
|
|
80588
|
-
capName: "addon-settings",
|
|
80589
|
-
capScope: "system",
|
|
80590
|
-
addonId: null,
|
|
80591
|
-
access: "view",
|
|
80592
|
-
role: "admin"
|
|
80593
|
-
},
|
|
80594
80560
|
"addonSettings.getScopedSettings": {
|
|
80595
80561
|
capName: "addon-settings",
|
|
80596
80562
|
capScope: "system",
|
|
@@ -88613,13 +88579,6 @@ Object.freeze({
|
|
|
88613
88579
|
access: "create",
|
|
88614
88580
|
role: "admin"
|
|
88615
88581
|
},
|
|
88616
|
-
"smtpProvider.verify": {
|
|
88617
|
-
capName: "smtp-provider",
|
|
88618
|
-
capScope: "system",
|
|
88619
|
-
addonId: null,
|
|
88620
|
-
access: "view",
|
|
88621
|
-
role: "admin"
|
|
88622
|
-
},
|
|
88623
88582
|
"snapshot.applyDeviceSettingsPatch": {
|
|
88624
88583
|
capName: "snapshot",
|
|
88625
88584
|
capScope: "device",
|
|
@@ -95597,28 +95556,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
95597
95556
|
};
|
|
95598
95557
|
return {
|
|
95599
95558
|
getStatus: async () => status(),
|
|
95600
|
-
verify: async () => {
|
|
95601
|
-
const account = selectGmailAccount(deps.accounts(), void 0);
|
|
95602
|
-
if (account === null) {
|
|
95603
|
-
lastError = "No Google broker connected.";
|
|
95604
|
-
return status();
|
|
95605
|
-
}
|
|
95606
|
-
try {
|
|
95607
|
-
const token = await account.getAccessToken();
|
|
95608
|
-
const res = await http(`${GOOGLE_GMAIL_API}/users/me/profile`, { headers: { Authorization: `Bearer ${token}` } });
|
|
95609
|
-
if (!res.ok) {
|
|
95610
|
-
const text = await res.text();
|
|
95611
|
-
lastError = `Gmail profile failed (${res.status}): ${text.slice(0, 200)}`;
|
|
95612
|
-
return status();
|
|
95613
|
-
}
|
|
95614
|
-
lastError = void 0;
|
|
95615
|
-
lastVerifiedAt = Date.now();
|
|
95616
|
-
return status();
|
|
95617
|
-
} catch (err) {
|
|
95618
|
-
lastError = err instanceof Error ? err.message : String(err);
|
|
95619
|
-
return status();
|
|
95620
|
-
}
|
|
95621
|
-
},
|
|
95622
95559
|
sendEmail: async (input) => {
|
|
95623
95560
|
const account = selectGmailAccount(deps.accounts(), input.from);
|
|
95624
95561
|
if (account === null) throw new Error("No Google broker connected — add one under Connectivity → Brokers and Connect.");
|
|
@@ -6012,7 +6012,7 @@ var ZodIssueCode = {
|
|
|
6012
6012
|
var ZodFirstPartyTypeKind;
|
|
6013
6013
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6014
6014
|
//#endregion
|
|
6015
|
-
//#region ../types/dist/sleep-
|
|
6015
|
+
//#region ../types/dist/sleep-CkinsFFb.mjs
|
|
6016
6016
|
/**
|
|
6017
6017
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6018
6018
|
* window to float samples (D455).
|
|
@@ -8691,16 +8691,6 @@ var BaseAddon = class {
|
|
|
8691
8691
|
return null;
|
|
8692
8692
|
}
|
|
8693
8693
|
/**
|
|
8694
|
-
* The form schema of ONE integration instance, or `null` to use the scoped form.
|
|
8695
|
-
*
|
|
8696
|
-
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
8697
|
-
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
8698
|
-
* SHAPE of the form only — the values live on the instance record.
|
|
8699
|
-
*/
|
|
8700
|
-
async integrationFormSchema(_instance) {
|
|
8701
|
-
return null;
|
|
8702
|
-
}
|
|
8703
|
-
/**
|
|
8704
8694
|
* D986 scoped settings: the form shape of the CLUSTER-wide settings one capability this addon
|
|
8705
8695
|
* provides owns, or `null` when it has none. `cap` is a capability name the addon's manifest
|
|
8706
8696
|
* declares. Stored as `addon-settings` rows `<addonId>.<field>`. The keys of this schema, of
|
|
@@ -8728,8 +8718,7 @@ var BaseAddon = class {
|
|
|
8728
8718
|
}
|
|
8729
8719
|
/**
|
|
8730
8720
|
* The host's read of the scoped declarations: the schema one capability declares for `scope`,
|
|
8731
|
-
* or `null`.
|
|
8732
|
-
* host asks this method.
|
|
8721
|
+
* or `null`. The hook is protected, the host asks this method.
|
|
8733
8722
|
*/
|
|
8734
8723
|
async getScopedSettingsSchema(scope, cap) {
|
|
8735
8724
|
switch (scope) {
|
|
@@ -8897,22 +8886,6 @@ var BaseAddon = class {
|
|
|
8897
8886
|
return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
|
|
8898
8887
|
}
|
|
8899
8888
|
/**
|
|
8900
|
-
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
8901
|
-
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8902
|
-
*/
|
|
8903
|
-
async getIntegrationFormSchema(instance, nodeId) {
|
|
8904
|
-
const scoped = await this.integrationFormSchema(instance);
|
|
8905
|
-
if (scoped === null) return this.scopedForm(nodeId);
|
|
8906
|
-
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8907
|
-
}
|
|
8908
|
-
/** The form of the scoped schemas this addon declared, hydrated from its store. */
|
|
8909
|
-
async scopedForm(nodeId) {
|
|
8910
|
-
await this.loadScopedSchemas();
|
|
8911
|
-
const schema = this.scopedFormSchema();
|
|
8912
|
-
if (!schema) return { sections: [] };
|
|
8913
|
-
return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
|
|
8914
|
-
}
|
|
8915
|
-
/**
|
|
8916
8889
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
8917
8890
|
* every `perNode: true` field carries THAT node's scoped value on its bare
|
|
8918
8891
|
* key (absent scoped key ⇒ key absent, so the schema `default` wins — no
|
|
@@ -9099,12 +9072,6 @@ var BaseAddon = class {
|
|
|
9099
9072
|
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
9100
9073
|
this._addonSecretTree = null;
|
|
9101
9074
|
}
|
|
9102
|
-
/** The form of an addon's scoped schemas: their sections, each shown once. */
|
|
9103
|
-
scopedFormSchema(cap) {
|
|
9104
|
-
const byId = /* @__PURE__ */ new Map();
|
|
9105
|
-
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
9106
|
-
return byId.size === 0 ? null : { sections: [...byId.values()] };
|
|
9107
|
-
}
|
|
9108
9075
|
/** Every loaded scoped schema of `cap`, or of every loaded capability. */
|
|
9109
9076
|
loadedScopedSchemas(cap) {
|
|
9110
9077
|
if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
|
|
@@ -9694,6 +9661,24 @@ function normalizeAddonInitResult(result) {
|
|
|
9694
9661
|
if (Array.isArray(result)) return { providers: result };
|
|
9695
9662
|
return result;
|
|
9696
9663
|
}
|
|
9664
|
+
object({
|
|
9665
|
+
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
9666
|
+
params: record(string(), union([string(), number$1()])).optional()
|
|
9667
|
+
});
|
|
9668
|
+
var CamstackError = class extends Error {
|
|
9669
|
+
i18nCode;
|
|
9670
|
+
i18nParams;
|
|
9671
|
+
constructor(code, params, englishMessage) {
|
|
9672
|
+
super(englishMessage);
|
|
9673
|
+
this.name = "CamstackError";
|
|
9674
|
+
this.i18nCode = code;
|
|
9675
|
+
this.i18nParams = params;
|
|
9676
|
+
}
|
|
9677
|
+
};
|
|
9678
|
+
/** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
|
|
9679
|
+
function userError(code, params, englishFallback) {
|
|
9680
|
+
return new CamstackError(code, params, englishFallback);
|
|
9681
|
+
}
|
|
9697
9682
|
object({
|
|
9698
9683
|
field: string().min(1),
|
|
9699
9684
|
on: literal("advance")
|
|
@@ -9770,12 +9755,6 @@ function systemMethod(input, output, options) {
|
|
|
9770
9755
|
systemOnly: true
|
|
9771
9756
|
};
|
|
9772
9757
|
}
|
|
9773
|
-
/**
|
|
9774
|
-
* A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
|
|
9775
|
-
* on `InferProvider`. The `providerOptional: true` literal is what
|
|
9776
|
-
* `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
|
|
9777
|
-
* for when this is the honest answer and when it is a soft stub.
|
|
9778
|
-
*/
|
|
9779
9758
|
function optionalMethod(input, output, options) {
|
|
9780
9759
|
return {
|
|
9781
9760
|
...method(input, output, options),
|
|
@@ -17170,24 +17149,6 @@ Object.freeze({
|
|
|
17170
17149
|
"uploadDataset": 72e5
|
|
17171
17150
|
}
|
|
17172
17151
|
});
|
|
17173
|
-
object({
|
|
17174
|
-
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
17175
|
-
params: record(string(), union([string(), number$1()])).optional()
|
|
17176
|
-
});
|
|
17177
|
-
var CamstackError = class extends Error {
|
|
17178
|
-
i18nCode;
|
|
17179
|
-
i18nParams;
|
|
17180
|
-
constructor(code, params, englishMessage) {
|
|
17181
|
-
super(englishMessage);
|
|
17182
|
-
this.name = "CamstackError";
|
|
17183
|
-
this.i18nCode = code;
|
|
17184
|
-
this.i18nParams = params;
|
|
17185
|
-
}
|
|
17186
|
-
};
|
|
17187
|
-
/** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
|
|
17188
|
-
function userError(code, params, englishFallback) {
|
|
17189
|
-
return new CamstackError(code, params, englishFallback);
|
|
17190
|
-
}
|
|
17191
17152
|
//#endregion
|
|
17192
17153
|
//#region ../types/dist/composition-CXCX78IR.mjs
|
|
17193
17154
|
/**
|
|
@@ -18899,25 +18860,6 @@ var RequiredAddonUpdateSchema = object({
|
|
|
18899
18860
|
installed: string().nullable()
|
|
18900
18861
|
});
|
|
18901
18862
|
/**
|
|
18902
|
-
* Which integration instance a settings form is for. An addon that serves several instances
|
|
18903
|
-
* (`instanceMode: multiple`) can show a different form per instance — an NVR integration
|
|
18904
|
-
* needs its connection, the default integration needs the addon's own sections.
|
|
18905
|
-
*
|
|
18906
|
-
* - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
|
|
18907
|
-
* setting up a NEW instance.
|
|
18908
|
-
* - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
|
|
18909
|
-
* - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
|
|
18910
|
-
*/
|
|
18911
|
-
var IntegrationInstanceRefSchema = object({
|
|
18912
|
-
integrationId: string().nullable(),
|
|
18913
|
-
mode: _enum([
|
|
18914
|
-
"standalone",
|
|
18915
|
-
"account",
|
|
18916
|
-
"broker"
|
|
18917
|
-
]),
|
|
18918
|
-
candidateStableId: string().optional()
|
|
18919
|
-
});
|
|
18920
|
-
/**
|
|
18921
18863
|
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
18922
18864
|
* both the operator-facing `getRoutes` (returning route descriptors
|
|
18923
18865
|
* minus the handlers, which can't cross JSON) and the framework-
|
|
@@ -19094,8 +19036,8 @@ function composeInstanceKinds(parts, base) {
|
|
|
19094
19036
|
instanceFormSchema: async ({ id, kind }) => {
|
|
19095
19037
|
return (id === null ? byKind(kind) : await holderOf(id)).provider.instanceFormSchema({ id });
|
|
19096
19038
|
},
|
|
19097
|
-
listInstances: async () => {
|
|
19098
|
-
return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances()).map((instance) => tagged(part, instance))))).flat();
|
|
19039
|
+
listInstances: async (input) => {
|
|
19040
|
+
return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances(input)).map((instance) => tagged(part, instance))))).flat();
|
|
19099
19041
|
},
|
|
19100
19042
|
getInstance: async ({ id }) => {
|
|
19101
19043
|
for (const part of parts) {
|
|
@@ -45240,10 +45182,6 @@ method(object({
|
|
|
45240
45182
|
scope: ScopedSettingsScopeSchema,
|
|
45241
45183
|
nodeId: string().optional()
|
|
45242
45184
|
}), record(string(), unknown()).nullable()), method(object({
|
|
45243
|
-
addonId: string(),
|
|
45244
|
-
nodeId: string().optional(),
|
|
45245
|
-
instance: IntegrationInstanceRefSchema
|
|
45246
|
-
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
45247
45185
|
addonId: string(),
|
|
45248
45186
|
nodeId: string().optional()
|
|
45249
45187
|
}), object({ keys: array(string()) }).nullable(), { auth: "admin" }), method(object({
|
|
@@ -55648,6 +55586,12 @@ var IntegrationWithStateSchema = object({
|
|
|
55648
55586
|
name: string(),
|
|
55649
55587
|
/** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
|
|
55650
55588
|
enabled: boolean(),
|
|
55589
|
+
/**
|
|
55590
|
+
* True when the addon that holds the switch did not answer (down, failed, or keeps no record for
|
|
55591
|
+
* this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
|
|
55592
|
+
* must not draw it as on or off (D315).
|
|
55593
|
+
*/
|
|
55594
|
+
switchUnknown: literal(true).optional(),
|
|
55651
55595
|
info: record(string(), unknown()).readonly(),
|
|
55652
55596
|
/** The discovery candidate this integration was set up from (D984). */
|
|
55653
55597
|
originStableId: string().optional(),
|
|
@@ -55661,6 +55605,12 @@ var IntegrationLiteSchema = object({
|
|
|
55661
55605
|
name: string(),
|
|
55662
55606
|
/** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
|
|
55663
55607
|
enabled: boolean(),
|
|
55608
|
+
/**
|
|
55609
|
+
* True when the addon that holds the switch did not answer (down, failed, or keeps no record for
|
|
55610
|
+
* this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
|
|
55611
|
+
* must not draw it as on or off (D315).
|
|
55612
|
+
*/
|
|
55613
|
+
switchUnknown: literal(true).optional(),
|
|
55664
55614
|
info: record(string(), unknown()).readonly(),
|
|
55665
55615
|
/** The discovery candidate this integration was set up from (D984). */
|
|
55666
55616
|
originStableId: string().optional(),
|
|
@@ -55759,9 +55709,9 @@ var UpdateIntegrationInputSchema = object({
|
|
|
55759
55709
|
id: string(),
|
|
55760
55710
|
name: string().optional(),
|
|
55761
55711
|
/**
|
|
55762
|
-
*
|
|
55763
|
-
*
|
|
55764
|
-
*
|
|
55712
|
+
* Honoured ONLY for a fixed builtin (`info.fixed`), whose switch is the hub's own registry flag
|
|
55713
|
+
* and works while its addon is down. Any other row is refused (a typed `BAD_REQUEST`): its
|
|
55714
|
+
* switch is `integration-instances.setInstanceEnabled`.
|
|
55765
55715
|
*/
|
|
55766
55716
|
enabled: boolean().optional(),
|
|
55767
55717
|
info: record(string(), unknown()).optional()
|
|
@@ -55795,6 +55745,12 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
55795
55745
|
* the form as a `SecretFieldView`, never text (D789). A patch value omitted, `''`
|
|
55796
55746
|
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
55797
55747
|
* clears it.
|
|
55748
|
+
*
|
|
55749
|
+
* Who may call (epic #440): every method but `describe` and `instanceFormSchema` is open to any
|
|
55750
|
+
* session (`caller: 'scoped'`) and default-denies. An admin passes everywhere. A non-admin passes
|
|
55751
|
+
* only on a call pinned to one addon whose `describe().userScoped` is true, and that provider
|
|
55752
|
+
* filters every row on the `caller` the router injected (a notification target is somebody's
|
|
55753
|
+
* phone: a user sees and changes only their own). An addon that says nothing keeps the admin door.
|
|
55798
55754
|
*/
|
|
55799
55755
|
var ConfigSchemaPassthrough$2 = custom();
|
|
55800
55756
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
@@ -55908,7 +55864,15 @@ var IntegrationInstanceDescriptionSchema = object({
|
|
|
55908
55864
|
*/
|
|
55909
55865
|
mintsId: boolean().optional(),
|
|
55910
55866
|
/** The links to other instances the provider's kinds declare; absent means none. */
|
|
55911
|
-
links: array(IntegrationInstanceLinkSchema).optional()
|
|
55867
|
+
links: array(IntegrationInstanceLinkSchema).optional(),
|
|
55868
|
+
/**
|
|
55869
|
+
* The rows belong to individual users (a notification target is somebody's phone). The router
|
|
55870
|
+
* then opens `listInstances`, `getInstance`, `createInstance`, `updateInstance`,
|
|
55871
|
+
* `setInstanceEnabled`, `deleteInstance` and `testInstance` to a NON-admin session on a call
|
|
55872
|
+
* pinned to this addon, and hands the provider the `caller` so it keeps a user to their own rows.
|
|
55873
|
+
* Absent means admin only, as it always was.
|
|
55874
|
+
*/
|
|
55875
|
+
userScoped: boolean().optional()
|
|
55912
55876
|
});
|
|
55913
55877
|
var IntegrationInstanceStatusSchema = object({
|
|
55914
55878
|
state: _enum([
|
|
@@ -55966,8 +55930,14 @@ var integrationInstancesCapability = {
|
|
|
55966
55930
|
/** The discovery candidate the wizard was seeded from (`stableId`), if any. */
|
|
55967
55931
|
candidateStableId: string().min(1).optional()
|
|
55968
55932
|
}), ConfigSchemaPassthrough$2, { auth: "admin" }),
|
|
55969
|
-
listInstances: method(
|
|
55970
|
-
|
|
55933
|
+
listInstances: method(looseObject({}), array(IntegrationInstanceSchema).readonly(), {
|
|
55934
|
+
auth: "protected",
|
|
55935
|
+
caller: "scoped"
|
|
55936
|
+
}),
|
|
55937
|
+
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), {
|
|
55938
|
+
auth: "protected",
|
|
55939
|
+
caller: "scoped"
|
|
55940
|
+
}),
|
|
55971
55941
|
/**
|
|
55972
55942
|
* Insert the typed record. With `id` it is stored under that id (a duplicate id is refused);
|
|
55973
55943
|
* without one the PROVIDER mints it and answers it. `kind` picks one of `describe().kinds`.
|
|
@@ -56000,11 +55970,13 @@ var integrationInstancesCapability = {
|
|
|
56000
55970
|
seed: object({ info: record(string(), unknown()) }).optional()
|
|
56001
55971
|
}), object({ id: string() }), {
|
|
56002
55972
|
kind: "mutation",
|
|
56003
|
-
auth: "
|
|
55973
|
+
auth: "protected",
|
|
55974
|
+
caller: "scoped"
|
|
56004
55975
|
}),
|
|
56005
55976
|
updateInstance: method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
56006
55977
|
kind: "mutation",
|
|
56007
|
-
auth: "
|
|
55978
|
+
auth: "protected",
|
|
55979
|
+
caller: "scoped"
|
|
56008
55980
|
}),
|
|
56009
55981
|
/**
|
|
56010
55982
|
* Switch ONE instance on or off, for every role; a missing record is created from the addon's
|
|
@@ -56016,7 +55988,8 @@ var integrationInstancesCapability = {
|
|
|
56016
55988
|
enabled: boolean()
|
|
56017
55989
|
}), object({ ok: literal(true) }), {
|
|
56018
55990
|
kind: "mutation",
|
|
56019
|
-
auth: "
|
|
55991
|
+
auth: "protected",
|
|
55992
|
+
caller: "scoped"
|
|
56020
55993
|
}),
|
|
56021
55994
|
/**
|
|
56022
55995
|
* Delete the record and its keychain refs together. For an instance that brings devices the hub
|
|
@@ -56025,7 +55998,8 @@ var integrationInstancesCapability = {
|
|
|
56025
55998
|
*/
|
|
56026
55999
|
deleteInstance: method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
56027
56000
|
kind: "mutation",
|
|
56028
|
-
auth: "
|
|
56001
|
+
auth: "protected",
|
|
56002
|
+
caller: "scoped"
|
|
56029
56003
|
}),
|
|
56030
56004
|
testInstance: optionalMethod(object({
|
|
56031
56005
|
id: IntegrationInstanceIdSchema.nullable(),
|
|
@@ -56034,7 +56008,8 @@ var integrationInstancesCapability = {
|
|
|
56034
56008
|
kind: string().min(1).optional()
|
|
56035
56009
|
}), TestConnectionResultSchema, {
|
|
56036
56010
|
kind: "mutation",
|
|
56037
|
-
auth: "
|
|
56011
|
+
auth: "protected",
|
|
56012
|
+
caller: "scoped"
|
|
56038
56013
|
})
|
|
56039
56014
|
}
|
|
56040
56015
|
};
|
|
@@ -73884,6 +73859,11 @@ var SendEmailResultSchema = object({
|
|
|
73884
73859
|
var SmtpStatusSchema = object({
|
|
73885
73860
|
/** True iff the addon has successfully verified the relay. */
|
|
73886
73861
|
ready: boolean(),
|
|
73862
|
+
/**
|
|
73863
|
+
* The tri-state behind `ready` (D315): true when the last send worked, false when it failed,
|
|
73864
|
+
* ABSENT when the relay has not sent yet (unknown, never "not verified").
|
|
73865
|
+
*/
|
|
73866
|
+
verified: boolean().optional(),
|
|
73887
73867
|
/** Operator-visible host string (no credentials). */
|
|
73888
73868
|
host: string(),
|
|
73889
73869
|
/** Last error message reported by the relay, when not ready. */
|
|
@@ -73903,13 +73883,6 @@ var smtpProviderCapability = {
|
|
|
73903
73883
|
auth: "admin",
|
|
73904
73884
|
access: "create"
|
|
73905
73885
|
}),
|
|
73906
|
-
/** Round-trip ping against the SMTP relay (EHLO + AUTH if configured).
|
|
73907
|
-
* Used by the operator's "Test connection" button. */
|
|
73908
|
-
verify: method(RelayPinSchema, SmtpStatusSchema, {
|
|
73909
|
-
kind: "mutation",
|
|
73910
|
-
auth: "admin",
|
|
73911
|
-
access: "view"
|
|
73912
|
-
}),
|
|
73913
73886
|
getStatus: method(RelayPinSchema, SmtpStatusSchema, { auth: "admin" })
|
|
73914
73887
|
}
|
|
73915
73888
|
};
|
|
@@ -80580,13 +80553,6 @@ Object.freeze({
|
|
|
80580
80553
|
access: "view",
|
|
80581
80554
|
role: "admin"
|
|
80582
80555
|
},
|
|
80583
|
-
"addonSettings.getIntegrationFormSchema": {
|
|
80584
|
-
capName: "addon-settings",
|
|
80585
|
-
capScope: "system",
|
|
80586
|
-
addonId: null,
|
|
80587
|
-
access: "view",
|
|
80588
|
-
role: "admin"
|
|
80589
|
-
},
|
|
80590
80556
|
"addonSettings.getScopedSettings": {
|
|
80591
80557
|
capName: "addon-settings",
|
|
80592
80558
|
capScope: "system",
|
|
@@ -88609,13 +88575,6 @@ Object.freeze({
|
|
|
88609
88575
|
access: "create",
|
|
88610
88576
|
role: "admin"
|
|
88611
88577
|
},
|
|
88612
|
-
"smtpProvider.verify": {
|
|
88613
|
-
capName: "smtp-provider",
|
|
88614
|
-
capScope: "system",
|
|
88615
|
-
addonId: null,
|
|
88616
|
-
access: "view",
|
|
88617
|
-
role: "admin"
|
|
88618
|
-
},
|
|
88619
88578
|
"snapshot.applyDeviceSettingsPatch": {
|
|
88620
88579
|
capName: "snapshot",
|
|
88621
88580
|
capScope: "device",
|
|
@@ -95593,28 +95552,6 @@ function createGmailSmtpProvider(deps) {
|
|
|
95593
95552
|
};
|
|
95594
95553
|
return {
|
|
95595
95554
|
getStatus: async () => status(),
|
|
95596
|
-
verify: async () => {
|
|
95597
|
-
const account = selectGmailAccount(deps.accounts(), void 0);
|
|
95598
|
-
if (account === null) {
|
|
95599
|
-
lastError = "No Google broker connected.";
|
|
95600
|
-
return status();
|
|
95601
|
-
}
|
|
95602
|
-
try {
|
|
95603
|
-
const token = await account.getAccessToken();
|
|
95604
|
-
const res = await http(`${GOOGLE_GMAIL_API}/users/me/profile`, { headers: { Authorization: `Bearer ${token}` } });
|
|
95605
|
-
if (!res.ok) {
|
|
95606
|
-
const text = await res.text();
|
|
95607
|
-
lastError = `Gmail profile failed (${res.status}): ${text.slice(0, 200)}`;
|
|
95608
|
-
return status();
|
|
95609
|
-
}
|
|
95610
|
-
lastError = void 0;
|
|
95611
|
-
lastVerifiedAt = Date.now();
|
|
95612
|
-
return status();
|
|
95613
|
-
} catch (err) {
|
|
95614
|
-
lastError = err instanceof Error ? err.message : String(err);
|
|
95615
|
-
return status();
|
|
95616
|
-
}
|
|
95617
|
-
},
|
|
95618
95555
|
sendEmail: async (input) => {
|
|
95619
95556
|
const account = selectGmailAccount(deps.accounts(), input.from);
|
|
95620
95557
|
if (account === null) throw new Error("No Google broker connected — add one under Connectivity → Brokers and Connect.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-google-services",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.46",
|
|
4
4
|
"description": "Google — Google brokers (OAuth2): Calendar as calendar-source, Gmail send as smtp-provider.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
66
|
"requires": {
|
|
67
|
-
"server": ">=1.2.
|
|
67
|
+
"server": ">=1.2.820"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"files": [
|