@raidiant/notifai 12.0.0-beta.6 → 12.0.0
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 +24 -10
- package/bin/notifai.mjs +115 -54
- package/data/install.ps1 +142 -11
- package/data/release.json +1 -1
- package/inventory.json +1 -1
- package/npm-adapter-files.json +14 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,21 +8,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
|
9
9
|
and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
|
10
10
|
|
|
11
|
-
## [12.0.0
|
|
11
|
+
## [12.0.0](https://github.com/Raidiant-io/notifai/compare/v11.8.0...v12.0.0) (2026-10-12)
|
|
12
12
|
|
|
13
|
-
### Breaking changes
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
### ⚠ BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* **cli:** unify native and npm installation
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **cli:** link a Claude Code picker by its questions, not a copied marker ([#278](https://github.com/Raidiant-io/notifai/issues/278)) ([449a4eb](https://github.com/Raidiant-io/notifai/commit/449a4ebe9de2284b808531675ee9f44f9f6978f1))
|
|
21
|
+
* **cli:** share one sign-in per machine with desktop apps ([#282](https://github.com/Raidiant-io/notifai/issues/282)) ([32863ba](https://github.com/Raidiant-io/notifai/commit/32863ba132261f706726664fd4796134a4d38eb6))
|
|
22
|
+
* **cli:** unify native and npm installation ([2ea7ef7](https://github.com/Raidiant-io/notifai/commit/2ea7ef735b75deee1deda7e08672ad0c757d0d0c))
|
|
23
|
+
* **protocol:** add desktop platforms, the stream provider and the changes feed ([#281](https://github.com/Raidiant-io/notifai/issues/281)) ([4b2bf51](https://github.com/Raidiant-io/notifai/commit/4b2bf51ecf5c120e5fa12141736f0df649f9fea5))
|
|
24
|
+
* **sounds:** add a bundled Update tone ([#289](https://github.com/Raidiant-io/notifai/issues/289)) ([31a7e5d](https://github.com/Raidiant-io/notifai/commit/31a7e5d103b318d7b8b10d1d29bd8c7964172dfe))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* **auth:** preserve Linux credential authority across sessions ([#285](https://github.com/Raidiant-io/notifai/issues/285)) ([ce1ec66](https://github.com/Raidiant-io/notifai/commit/ce1ec66ea6f6078132b474a5b708107438d9017c))
|
|
30
|
+
* **cli:** link grouped Claude questions across registrations ([#288](https://github.com/Raidiant-io/notifai/issues/288)) ([b2e1bc4](https://github.com/Raidiant-io/notifai/commit/b2e1bc46d68c25dbf7a79bc67f88898d66ec720b))
|
|
31
|
+
* **cli:** preserve activity verification through long Codex turns ([#276](https://github.com/Raidiant-io/notifai/issues/276)) ([151ba68](https://github.com/Raidiant-io/notifai/commit/151ba687effee47ccef65f3800502ea896cd76dc))
|
|
32
|
+
* **cli:** stop reporting an acknowledgement as still required after recording it ([#277](https://github.com/Raidiant-io/notifai/issues/277)) ([0c4b363](https://github.com/Raidiant-io/notifai/commit/0c4b36358c9ff0616732043611aeebdcfd6cf4dd))
|
|
16
33
|
|
|
17
|
-
### Improvements
|
|
18
34
|
|
|
19
|
-
|
|
35
|
+
### Dependencies
|
|
20
36
|
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Verify npm adapter bytes against the signed native release and coordinate publication across all supported targets.
|
|
25
|
-
* Keep long Codex turns readable and link Claude question-picker content to its registered question.
|
|
37
|
+
* The following workspace dependencies were updated
|
|
38
|
+
* dependencies
|
|
39
|
+
* @raidiant/notifai-protocol bumped from 8.2.2 to 8.3.0
|
|
26
40
|
|
|
27
41
|
## [11.8.0](https://github.com/Raidiant-io/notifai/compare/v11.7.1...v11.8.0) (2026-10-08)
|
|
28
42
|
|
package/bin/notifai.mjs
CHANGED
|
@@ -7031,7 +7031,7 @@ var init_zip_reader = __esm({
|
|
|
7031
7031
|
});
|
|
7032
7032
|
|
|
7033
7033
|
// apps/cli/npm/main.mjs
|
|
7034
|
-
import { readFileSync as readFileSync5, lstatSync as
|
|
7034
|
+
import { readFileSync as readFileSync5, lstatSync as lstatSync6 } from "node:fs";
|
|
7035
7035
|
import path7 from "node:path";
|
|
7036
7036
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7037
7037
|
|
|
@@ -7053,6 +7053,13 @@ function isPrerelease(value) {
|
|
|
7053
7053
|
return SEMVER.exec(value)?.[4] !== void 0;
|
|
7054
7054
|
}
|
|
7055
7055
|
|
|
7056
|
+
// apps/cli/src/local-continuity.ts
|
|
7057
|
+
function localContinuity(value) {
|
|
7058
|
+
const item = value;
|
|
7059
|
+
if (!item || typeof item.contract !== "string" || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(item.contract)) throw new Error("Invalid local continuity contract");
|
|
7060
|
+
return { contract: item.contract };
|
|
7061
|
+
}
|
|
7062
|
+
|
|
7056
7063
|
// apps/cli/src/release-distribution.ts
|
|
7057
7064
|
var RELEASE_TARGETS = [
|
|
7058
7065
|
"bun-darwin-arm64",
|
|
@@ -7111,11 +7118,19 @@ var Distribution = class {
|
|
|
7111
7118
|
const publicKey = createPublicKey(key);
|
|
7112
7119
|
if (publicKey.asymmetricKeyType !== "ed25519" || signature.length !== 64 || !verify(null, releaseSigningMessage(kind, payload), publicKey, signature)) throw new Error("Invalid release signature");
|
|
7113
7120
|
const value = JSON.parse(payload.toString("utf8"));
|
|
7114
|
-
if (!record(value) || value["schema"] !== 1
|
|
7121
|
+
if (!record(value) || value["schema"] !== 1 && !(kind === "inventory" && value["schema"] === 2)) {
|
|
7122
|
+
throw new Error("Unsupported release record schema");
|
|
7123
|
+
}
|
|
7115
7124
|
return value;
|
|
7116
7125
|
}
|
|
7117
7126
|
verifyInventory(bytes) {
|
|
7118
7127
|
const value = this.verifyRecord("inventory", bytes);
|
|
7128
|
+
if (value["schema"] === 2) {
|
|
7129
|
+
const continuity = localContinuity(value["local_continuity"]);
|
|
7130
|
+
value["local_continuity"] = Object.freeze(continuity);
|
|
7131
|
+
} else if (value["local_continuity"] !== void 0) {
|
|
7132
|
+
throw new Error("Historical inventory cannot declare an enforcing continuity contract");
|
|
7133
|
+
}
|
|
7119
7134
|
if (!version(value["version"]) || typeof value["source_revision"] !== "string" || !/^[a-f0-9]{40}$/.test(value["source_revision"]) || !positive(value["store_schema"]) || !positive(value["launcher_schema"]) || !Array.isArray(value["artifacts"]) || value["artifacts"].length === 0 || value["artifacts"].length > RELEASE_TARGETS.length) {
|
|
7120
7135
|
throw new Error("Malformed release inventory");
|
|
7121
7136
|
}
|
|
@@ -7260,6 +7275,20 @@ var NPM_ADAPTER_MANIFEST = "npm-adapter-files.json";
|
|
|
7260
7275
|
var NPM_ADAPTER_INVENTORY = "inventory.json";
|
|
7261
7276
|
var NPM_ADAPTER_MAX_METADATA = 256 * 1024;
|
|
7262
7277
|
var NPM_ADAPTER_MAX_BYTES = 16 * 1024 * 1024;
|
|
7278
|
+
function assertNpmAdapterPackage(value, manifest) {
|
|
7279
|
+
const pkg = value;
|
|
7280
|
+
const bin = pkg?.["bin"];
|
|
7281
|
+
if (!pkg || pkg["name"] !== manifest.package || pkg["version"] !== manifest.adapter_version || !bin || typeof bin !== "object" || Array.isArray(bin) || Object.keys(bin).length !== 1 || bin["notifai"] !== NPM_ADAPTER_BIN || [
|
|
7282
|
+
"scripts",
|
|
7283
|
+
"dependencies",
|
|
7284
|
+
"optionalDependencies",
|
|
7285
|
+
"peerDependencies",
|
|
7286
|
+
"bundleDependencies",
|
|
7287
|
+
"bundledDependencies",
|
|
7288
|
+
"directories",
|
|
7289
|
+
"man"
|
|
7290
|
+
].some((key) => Object.hasOwn(pkg, key))) throw new Error("Invalid published npm adapter package contract");
|
|
7291
|
+
}
|
|
7263
7292
|
function npmAdapterInventoryUrl(version2) {
|
|
7264
7293
|
if (version2.length > 100 || !isSemVer(version2)) throw new Error("Invalid npm adapter version");
|
|
7265
7294
|
return `https://github.com/Raidiant-io/notifai/releases/download/v${version2}/inventory.json`;
|
|
@@ -7292,24 +7321,41 @@ function parseNpmAdapterManifest(bytes) {
|
|
|
7292
7321
|
|
|
7293
7322
|
// apps/cli/src/npm-adapter-verification.ts
|
|
7294
7323
|
var hash = (bytes) => createHash2("sha256").update(bytes).digest("hex");
|
|
7295
|
-
function npmAdapterPosixAccess(
|
|
7324
|
+
function npmAdapterPosixAccess(paths) {
|
|
7296
7325
|
if (process.platform === "win32" || !process.getuid) throw new Error("Npm adapter ownership needs an OS access check");
|
|
7297
|
-
const
|
|
7298
|
-
|
|
7326
|
+
for (const { file } of paths) {
|
|
7327
|
+
const stat = lstatSync(file);
|
|
7328
|
+
if (stat.uid !== process.getuid() || (stat.mode & 18) !== 0) throw new Error("Npm adapter path is not owned by this User");
|
|
7329
|
+
}
|
|
7299
7330
|
}
|
|
7300
7331
|
function verifyNpmAdapterArtifact(directory, distribution, checkAccess = npmAdapterPosixAccess) {
|
|
7301
7332
|
directory = path.resolve(directory);
|
|
7333
|
+
const paths = [];
|
|
7334
|
+
const files = /* @__PURE__ */ new Map();
|
|
7302
7335
|
function inspect(file, isDirectory) {
|
|
7303
7336
|
const stat = lstatSync(file);
|
|
7304
7337
|
if (stat.isSymbolicLink() || (isDirectory ? !stat.isDirectory() : !stat.isFile())) {
|
|
7305
7338
|
throw new Error("Npm adapter contains a linked or non-regular path");
|
|
7306
7339
|
}
|
|
7307
|
-
|
|
7340
|
+
paths.push({ file, directory: isDirectory });
|
|
7308
7341
|
return stat;
|
|
7309
7342
|
}
|
|
7310
7343
|
inspect(directory, true);
|
|
7344
|
+
function collect(relative = "") {
|
|
7345
|
+
for (const name of readdirSync(path.join(directory, relative))) {
|
|
7346
|
+
if (paths.length > 256) throw new Error("Npm adapter contains too many paths");
|
|
7347
|
+
const local = relative ? `${relative}/${name}` : name, file = path.join(directory, local);
|
|
7348
|
+
const stat = lstatSync(file), isDirectory = stat.isDirectory();
|
|
7349
|
+
inspect(file, isDirectory);
|
|
7350
|
+
files.set(local, stat);
|
|
7351
|
+
if (isDirectory) collect(local);
|
|
7352
|
+
}
|
|
7353
|
+
}
|
|
7354
|
+
collect();
|
|
7355
|
+
checkAccess(paths);
|
|
7311
7356
|
function metadata(name) {
|
|
7312
|
-
const file = path.join(directory, name), stat =
|
|
7357
|
+
const file = path.join(directory, name), stat = files.get(name);
|
|
7358
|
+
if (!stat?.isFile()) throw new Error("Npm adapter metadata is missing or non-regular");
|
|
7313
7359
|
if (stat.size > NPM_ADAPTER_MAX_METADATA) throw new Error("Npm adapter metadata exceeds its size limit");
|
|
7314
7360
|
return readFileSync(file, "utf8");
|
|
7315
7361
|
}
|
|
@@ -7321,32 +7367,22 @@ function verifyNpmAdapterArtifact(directory, distribution, checkAccess = npmAdap
|
|
|
7321
7367
|
throw new Error("Npm adapter manifest is not authenticated by its native release");
|
|
7322
7368
|
}
|
|
7323
7369
|
const expected = new Map(manifest.files.map((file) => [file.path, file]));
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
if (
|
|
7328
|
-
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
visit(local);
|
|
7334
|
-
} else {
|
|
7335
|
-
inspect(file, false);
|
|
7336
|
-
if ([NPM_ADAPTER_MANIFEST, NPM_ADAPTER_INVENTORY].includes(local)) continue;
|
|
7337
|
-
const wanted = expected.get(local);
|
|
7338
|
-
if (!wanted || stat.size !== wanted.bytes || hash(readFileSync(file)) !== wanted.sha256) {
|
|
7339
|
-
throw new Error("Npm adapter payload integrity mismatch");
|
|
7340
|
-
}
|
|
7341
|
-
expected.delete(local);
|
|
7370
|
+
for (const [local, stat] of files) {
|
|
7371
|
+
const file = path.join(directory, local);
|
|
7372
|
+
if (stat.isDirectory()) {
|
|
7373
|
+
if (![...expected.keys()].some((item) => item.startsWith(`${local}/`))) throw new Error("Unexpected npm adapter directory");
|
|
7374
|
+
} else {
|
|
7375
|
+
if ([NPM_ADAPTER_MANIFEST, NPM_ADAPTER_INVENTORY].includes(local)) continue;
|
|
7376
|
+
const wanted = expected.get(local);
|
|
7377
|
+
if (!wanted || stat.size !== wanted.bytes || hash(readFileSync(file)) !== wanted.sha256) {
|
|
7378
|
+
throw new Error("Npm adapter payload integrity mismatch");
|
|
7342
7379
|
}
|
|
7380
|
+
expected.delete(local);
|
|
7343
7381
|
}
|
|
7344
7382
|
}
|
|
7345
|
-
visit();
|
|
7346
7383
|
if (expected.size) throw new Error("Npm adapter payload is incomplete");
|
|
7347
7384
|
const executable = path.join(directory, NPM_ADAPTER_BIN);
|
|
7348
|
-
|
|
7349
|
-
if (pkg.name !== manifest.package || pkg.version !== manifest.adapter_version || pkg.bin?.notifai !== NPM_ADAPTER_BIN || pkg.scripts !== void 0 || pkg.dependencies !== void 0) throw new Error("Invalid published npm adapter package contract");
|
|
7385
|
+
assertNpmAdapterPackage(JSON.parse(metadata("package.json")), manifest);
|
|
7350
7386
|
return { directory, executable, manifest, inventory, signedInventory };
|
|
7351
7387
|
}
|
|
7352
7388
|
|
|
@@ -10703,12 +10739,12 @@ function assertCurrentUserOwns(file, owner) {
|
|
|
10703
10739
|
var MAX_EXPANDED = 768 * 1024 * 1024;
|
|
10704
10740
|
var MAX_FILE = 512 * 1024 * 1024;
|
|
10705
10741
|
var MAX_ENTRIES = 130;
|
|
10706
|
-
async function tarEntries(bytes, consume) {
|
|
10742
|
+
async function tarEntries(bytes, consume, maxExpanded = MAX_EXPANDED) {
|
|
10707
10743
|
const reader = (0, import_tar_stream.extract)();
|
|
10708
10744
|
let expanded = 0;
|
|
10709
10745
|
const limit = new Transform({ transform(chunk, _encoding, done) {
|
|
10710
10746
|
expanded += chunk.length;
|
|
10711
|
-
done(expanded >
|
|
10747
|
+
done(expanded > maxExpanded ? new Error("Archive expanded size exceeds its limit") : null, chunk);
|
|
10712
10748
|
} });
|
|
10713
10749
|
const pumping = pipeline(
|
|
10714
10750
|
Readable.from([bytes]),
|
|
@@ -10880,11 +10916,11 @@ async function acquireNative(release, { distribution, platform, capture = false,
|
|
|
10880
10916
|
}
|
|
10881
10917
|
|
|
10882
10918
|
// apps/cli/src/npm-adapter-route.ts
|
|
10883
|
-
import { lstatSync as
|
|
10919
|
+
import { lstatSync as lstatSync4, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
10884
10920
|
import path5 from "node:path";
|
|
10885
10921
|
|
|
10886
10922
|
// apps/cli/src/local-path.ts
|
|
10887
|
-
import { realpathSync } from "node:fs";
|
|
10923
|
+
import { lstatSync as lstatSync3, readlinkSync, realpathSync } from "node:fs";
|
|
10888
10924
|
import path4 from "node:path";
|
|
10889
10925
|
function canonicalPath(file) {
|
|
10890
10926
|
const absolute = path4.resolve(file);
|
|
@@ -10999,8 +11035,8 @@ function inspectNpmAdapterRoute(command, proof, options = {}) {
|
|
|
10999
11035
|
const platform = options.platform ?? process.platform, access = options.checkAccess ?? npmAdapterPosixAccess;
|
|
11000
11036
|
try {
|
|
11001
11037
|
const candidate = path5.resolve(command), root = path5.resolve(proof.directory);
|
|
11002
|
-
if (sameLocalPath(candidate, proof.executable, platform) && !
|
|
11003
|
-
access(candidate, false);
|
|
11038
|
+
if (sameLocalPath(candidate, proof.executable, platform) && !lstatSync4(candidate).isSymbolicLink()) {
|
|
11039
|
+
access([{ file: candidate, directory: false }]);
|
|
11004
11040
|
return { kind: "direct", command: candidate, directory: path5.dirname(candidate), global_prefix: null, temporary_bin: null };
|
|
11005
11041
|
}
|
|
11006
11042
|
const route = placement(proof, platform);
|
|
@@ -11008,28 +11044,31 @@ function inspectNpmAdapterRoute(command, proof, options = {}) {
|
|
|
11008
11044
|
const name = path5.basename(candidate).toLowerCase();
|
|
11009
11045
|
if (!(platform === "win32" ? ["notifai", "notifai.cmd", "notifai.ps1"] : ["notifai"]).includes(name)) return null;
|
|
11010
11046
|
const stop = route.global_prefix ?? (route.kind === "npx" ? path5.dirname(path5.dirname(path5.dirname(route.directory))) : path5.dirname(path5.dirname(route.directory)));
|
|
11047
|
+
const directories = /* @__PURE__ */ new Set();
|
|
11011
11048
|
for (const start of [root, route.directory]) {
|
|
11012
11049
|
let current = start;
|
|
11013
11050
|
for (let depth = 0; depth < 16; depth++) {
|
|
11014
|
-
const stat2 =
|
|
11051
|
+
const stat2 = lstatSync4(current);
|
|
11015
11052
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
11016
|
-
|
|
11053
|
+
directories.add(current);
|
|
11017
11054
|
if (sameLocalPath(current, stop, platform)) break;
|
|
11018
11055
|
const parent = path5.dirname(current);
|
|
11019
11056
|
if (parent === current || depth === 15) return null;
|
|
11020
11057
|
current = parent;
|
|
11021
11058
|
}
|
|
11022
11059
|
}
|
|
11023
|
-
const stat =
|
|
11060
|
+
const stat = lstatSync4(candidate);
|
|
11024
11061
|
if (platform !== "win32") {
|
|
11025
11062
|
if (!stat.isSymbolicLink() || !process.getuid || stat.uid !== process.getuid() || !sameLocalPath(realpathSync2(candidate), proof.executable, platform)) return null;
|
|
11026
11063
|
} else {
|
|
11027
11064
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 16 * 1024) return null;
|
|
11028
|
-
access(candidate, false);
|
|
11029
11065
|
const relative = path5.relative(route.directory, proof.executable);
|
|
11030
11066
|
const bytes = readFileSync3(candidate, "utf8").replaceAll("\r\n", "\n");
|
|
11031
11067
|
if (bytes !== npmShim(relative, path5.extname(name))) return null;
|
|
11032
11068
|
}
|
|
11069
|
+
access([...directories].map((file) => ({ file, directory: true })).concat(
|
|
11070
|
+
platform === "win32" ? [{ file: candidate, directory: false }] : []
|
|
11071
|
+
));
|
|
11033
11072
|
return { ...route, command: candidate };
|
|
11034
11073
|
} catch {
|
|
11035
11074
|
return null;
|
|
@@ -11180,41 +11219,61 @@ async function runNpmAdapter(args, { locator, platform, distribution, verify: ve
|
|
|
11180
11219
|
import assert3 from "node:assert/strict";
|
|
11181
11220
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
11182
11221
|
import { randomUUID } from "node:crypto";
|
|
11183
|
-
import { lstatSync as
|
|
11222
|
+
import { lstatSync as lstatSync5, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
11184
11223
|
import os from "node:os";
|
|
11185
11224
|
import path6 from "node:path";
|
|
11186
11225
|
import { fileURLToPath } from "node:url";
|
|
11187
|
-
function powershell(operation, data = {}) {
|
|
11226
|
+
function powershell(operation, data = {}, { lineInput = false, execute = execFileSync } = {}) {
|
|
11188
11227
|
const script = fileURLToPath(new URL("../data/install.ps1", import.meta.url)).replaceAll("'", "''");
|
|
11189
11228
|
const payload = Buffer.from(JSON.stringify(data), "utf8").toString("base64");
|
|
11190
11229
|
const phase = (name) => `[Console]::Error.WriteLine('notifai-bootstrap:${name}');`;
|
|
11191
|
-
const
|
|
11230
|
+
const input = lineInput ? "[Console]::ReadLine()" : `'${payload}'`;
|
|
11231
|
+
const code = `${phase("started")} $ErrorActionPreference='Stop'; $ProgressPreference='SilentlyContinue'; $PSModuleAutoLoadingPreference='None'; Import-Module ([IO.Path]::Combine($PSHOME,'Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1')); ${phase("modules-ready")} [Console]::OutputEncoding=[Text.UTF8Encoding]::new($false); ${phase("encoding-ready")} . '${script}'; ${phase("helper-ready")} $inputData=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(${input})) | ConvertFrom-Json; ${phase("operation-started")} ${operation}; ${phase("complete")}`;
|
|
11192
11232
|
const systemRoot = process.env.SystemRoot;
|
|
11193
11233
|
assert3.ok(systemRoot && path6.win32.isAbsolute(systemRoot), "The OS PowerShell location is unavailable");
|
|
11194
11234
|
const executable = path6.join(systemRoot, "System32/WindowsPowerShell/v1.0/powershell.exe");
|
|
11195
11235
|
const encoded = Buffer.from(code, "utf16le").toString("base64");
|
|
11196
11236
|
assert3.ok(encoded.length + executable.length + 256 < 32767, "Installer pathname exceeds the Windows command-line limit");
|
|
11197
11237
|
try {
|
|
11198
|
-
return
|
|
11238
|
+
return execute(
|
|
11199
11239
|
executable,
|
|
11200
11240
|
["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", encoded],
|
|
11201
|
-
{
|
|
11241
|
+
{
|
|
11242
|
+
stdio: [lineInput ? "pipe" : "ignore", "pipe", "pipe"],
|
|
11243
|
+
...lineInput ? { input: payload + "\n" } : {},
|
|
11244
|
+
encoding: "utf8",
|
|
11245
|
+
timeout: 3e4,
|
|
11246
|
+
maxBuffer: 256 * 1024,
|
|
11247
|
+
windowsHide: true
|
|
11248
|
+
}
|
|
11202
11249
|
).trim();
|
|
11203
11250
|
} catch (error) {
|
|
11204
11251
|
const last = [...String(error.stderr ?? "").matchAll(/notifai-bootstrap:([a-z-]+)/g)].at(-1)?.[1] ?? "process-start";
|
|
11205
11252
|
throw new Error(`Windows installation helper failed after ${last} (${error.code ?? error.status ?? "unknown"}).`, { cause: error });
|
|
11206
11253
|
}
|
|
11207
11254
|
}
|
|
11255
|
+
function windowsPackageAccess(paths, execute = execFileSync) {
|
|
11256
|
+
assert3.ok(Array.isArray(paths) && paths.length > 0 && paths.length <= 257, "Invalid npm access batch size");
|
|
11257
|
+
for (const entry of paths) {
|
|
11258
|
+
assert3.ok(typeof entry.file === "string" && path6.isAbsolute(entry.file) && !entry.file.includes("\0") && typeof entry.directory === "boolean", "Invalid npm access path");
|
|
11259
|
+
}
|
|
11260
|
+
assert3.ok(Buffer.byteLength(JSON.stringify(paths)) <= 1024 * 1024, "Npm access batch exceeds its size limit");
|
|
11261
|
+
powershell(
|
|
11262
|
+
"foreach ($entry in $inputData.paths) { $attributes=[IO.File]::GetAttributes($entry.file); if ((($attributes -band [IO.FileAttributes]::Directory) -ne 0) -ne $entry.directory) { throw 'Npm adapter path type changed' }; Assert-NotifaiPathAccess $entry.file -AllowDefaultOwner }",
|
|
11263
|
+
{ paths },
|
|
11264
|
+
{ lineInput: true, execute }
|
|
11265
|
+
);
|
|
11266
|
+
}
|
|
11208
11267
|
function ownedPosixCommand(home, uid = process.getuid()) {
|
|
11209
11268
|
const command = path6.join(home, ".notifai/bin/notifai");
|
|
11210
11269
|
try {
|
|
11211
|
-
|
|
11270
|
+
lstatSync5(command);
|
|
11212
11271
|
} catch (error) {
|
|
11213
11272
|
if (error.code === "ENOENT") return null;
|
|
11214
11273
|
throw error;
|
|
11215
11274
|
}
|
|
11216
11275
|
for (const file of [home, path6.join(home, ".notifai"), path6.dirname(command), command]) {
|
|
11217
|
-
const stat =
|
|
11276
|
+
const stat = lstatSync5(file);
|
|
11218
11277
|
assert3.ok(
|
|
11219
11278
|
!stat.isSymbolicLink() && stat.uid === uid && (stat.mode & 18) === 0 && (file === command ? stat.isFile() && (stat.mode & 64) !== 0 : stat.isDirectory()),
|
|
11220
11279
|
"Existing installation is not privately owned; inspect it before repair"
|
|
@@ -11227,7 +11286,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
|
|
|
11227
11286
|
for (const directory of [home, root]) {
|
|
11228
11287
|
let stat;
|
|
11229
11288
|
try {
|
|
11230
|
-
stat =
|
|
11289
|
+
stat = lstatSync5(directory);
|
|
11231
11290
|
} catch (error) {
|
|
11232
11291
|
if (directory === root && error.code === "ENOENT") return;
|
|
11233
11292
|
throw error;
|
|
@@ -11238,7 +11297,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
|
|
|
11238
11297
|
}
|
|
11239
11298
|
for (const name of ["uninstall.json", "transaction.json", "install.json", "active.json"]) {
|
|
11240
11299
|
try {
|
|
11241
|
-
|
|
11300
|
+
lstatSync5(path6.join(root, name));
|
|
11242
11301
|
} catch (error) {
|
|
11243
11302
|
if (error.code === "ENOENT") continue;
|
|
11244
11303
|
throw error;
|
|
@@ -11249,7 +11308,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
|
|
|
11249
11308
|
const directory = path6.join(root, name);
|
|
11250
11309
|
let stat;
|
|
11251
11310
|
try {
|
|
11252
|
-
stat =
|
|
11311
|
+
stat = lstatSync5(directory);
|
|
11253
11312
|
} catch (error) {
|
|
11254
11313
|
if (error.code === "ENOENT") continue;
|
|
11255
11314
|
throw error;
|
|
@@ -11319,15 +11378,17 @@ function nativePlatform() {
|
|
|
11319
11378
|
},
|
|
11320
11379
|
assertAcquisitionReady() {
|
|
11321
11380
|
assert3.ok(home, "Resolve the OS account home before acquisition");
|
|
11322
|
-
assertAcquisitionReady(home, windows ? (file) => powershell("Assert-NotifaiPathAccess $inputData.file", { file }) : this.checkAccess, windows ? (file) => powershell("Assert-NotifaiPathAccess $inputData.file -AccountHome", { file }) : this.checkAccess);
|
|
11381
|
+
assertAcquisitionReady(home, windows ? (file) => powershell("Assert-NotifaiPathAccess $inputData.file", { file }) : (file, directory) => this.checkAccess([{ file, directory }]), windows ? (file) => powershell("Assert-NotifaiPathAccess $inputData.file -AccountHome", { file }) : (file, directory) => this.checkAccess([{ file, directory }]));
|
|
11323
11382
|
},
|
|
11324
|
-
checkAccess(
|
|
11383
|
+
checkAccess(paths) {
|
|
11325
11384
|
if (!windows) {
|
|
11326
|
-
const
|
|
11327
|
-
|
|
11385
|
+
for (const { file } of paths) {
|
|
11386
|
+
const stat = lstatSync5(file);
|
|
11387
|
+
assert3.ok(stat.uid === process.getuid() && (stat.mode & 18) === 0, "Npm adapter path is not owned by this User");
|
|
11388
|
+
}
|
|
11328
11389
|
return;
|
|
11329
11390
|
}
|
|
11330
|
-
|
|
11391
|
+
windowsPackageAccess(paths);
|
|
11331
11392
|
},
|
|
11332
11393
|
target() {
|
|
11333
11394
|
if (windows) return powershell("Get-NotifaiWindowsTarget");
|
|
@@ -11370,7 +11431,7 @@ function nativePlatform() {
|
|
|
11370
11431
|
try {
|
|
11371
11432
|
const root = path7.resolve(path7.dirname(fileURLToPath2(import.meta.url)), "..");
|
|
11372
11433
|
const file = path7.join(root, "data/release.json");
|
|
11373
|
-
const stat =
|
|
11434
|
+
const stat = lstatSync6(file);
|
|
11374
11435
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024) throw new Error("Invalid npm adapter release locator");
|
|
11375
11436
|
const locator = JSON.parse(readFileSync5(file, "utf8"));
|
|
11376
11437
|
const platform = nativePlatform(), distribution = new Distribution(RELEASE_PUBLIC_KEYS);
|
package/data/install.ps1
CHANGED
|
@@ -9,7 +9,8 @@ param(
|
|
|
9
9
|
[switch]$Json,
|
|
10
10
|
[switch]$NoInit,
|
|
11
11
|
[switch]$NoPath,
|
|
12
|
-
[switch]$MigrateNpm
|
|
12
|
+
[switch]$MigrateNpm,
|
|
13
|
+
[switch]$Upgrade
|
|
13
14
|
)
|
|
14
15
|
Set-StrictMode -Version Latest
|
|
15
16
|
$ErrorActionPreference = 'Stop'
|
|
@@ -147,9 +148,38 @@ function Expand-NotifaiArchive([string]$Archive, [string]$Destination) {
|
|
|
147
148
|
}
|
|
148
149
|
} finally { $zip.Dispose() }
|
|
149
150
|
}
|
|
151
|
+
function Add-NotifaiBootstrapType([string]$Source) {
|
|
152
|
+
if ($PSVersionTable.PSEdition -ne 'Desktop') { Add-Type -TypeDefinition $Source -ErrorAction Stop; return }
|
|
153
|
+
# Framework CodeDom passes csc an ANSI environment block. Keep its temporary
|
|
154
|
+
# paths relative even when the User's profile/TEMP contains non-ANSI text.
|
|
155
|
+
# Only this synchronous compiler invocation changes process-local cwd/env.
|
|
156
|
+
$scratch = [IO.Path]::Combine([IO.Path]::GetTempPath(), 'notifai-compiler-' + [Guid]::NewGuid().ToString('N'))
|
|
157
|
+
New-NotifaiPrivateDirectory $scratch
|
|
158
|
+
$previousDirectory = [Environment]::CurrentDirectory
|
|
159
|
+
$previousTemp = $env:TEMP
|
|
160
|
+
$previousTmp = $env:TMP
|
|
161
|
+
$parameters = [CodeDom.Compiler.CompilerParameters]::new()
|
|
162
|
+
$parameters.GenerateInMemory = $true
|
|
163
|
+
[void]$parameters.ReferencedAssemblies.Add([ComponentModel.Win32Exception].Assembly.Location)
|
|
164
|
+
$parameters.TempFiles = [CodeDom.Compiler.TempFileCollection]::new('.', $false)
|
|
165
|
+
try {
|
|
166
|
+
[Environment]::CurrentDirectory = $scratch
|
|
167
|
+
$env:TEMP = '.'
|
|
168
|
+
$env:TMP = '.'
|
|
169
|
+
Add-Type -TypeDefinition $Source -CompilerParameters $parameters -ErrorAction Stop
|
|
170
|
+
} finally {
|
|
171
|
+
try { $parameters.TempFiles.Dispose() }
|
|
172
|
+
finally {
|
|
173
|
+
[Environment]::CurrentDirectory = $previousDirectory
|
|
174
|
+
$env:TEMP = $previousTemp
|
|
175
|
+
$env:TMP = $previousTmp
|
|
176
|
+
[IO.Directory]::Delete($scratch, $true)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
150
180
|
function Get-NotifaiWindowsTarget {
|
|
151
181
|
if (-not ('NotifaiBootstrap.Native' -as [type])) {
|
|
152
|
-
Add-
|
|
182
|
+
Add-NotifaiBootstrapType @'
|
|
153
183
|
using System;
|
|
154
184
|
using System.Runtime.InteropServices;
|
|
155
185
|
namespace NotifaiBootstrap {
|
|
@@ -215,15 +245,113 @@ function Get-NotifaiAccountHome {
|
|
|
215
245
|
}
|
|
216
246
|
return $accountHome
|
|
217
247
|
}
|
|
248
|
+
# Read the descriptor and physical location through one non-following handle.
|
|
249
|
+
# Package capabilities restrict a User's access; they do not replace it.
|
|
250
|
+
# Only the registered package owning this current-User npm location is admitted.
|
|
251
|
+
function Get-NotifaiPathSecurity([string]$File, [bool]$Package) {
|
|
252
|
+
if (-not ('NotifaiBootstrap.PathSecurity' -as [type])) {
|
|
253
|
+
Add-NotifaiBootstrapType @'
|
|
254
|
+
using System;
|
|
255
|
+
using System.IO;
|
|
256
|
+
using System.Text;
|
|
257
|
+
using System.ComponentModel;
|
|
258
|
+
using System.Runtime.InteropServices;
|
|
259
|
+
using System.Security.AccessControl;
|
|
260
|
+
using System.Security.Principal;
|
|
261
|
+
using Microsoft.Win32.SafeHandles;
|
|
262
|
+
namespace NotifaiBootstrap {
|
|
263
|
+
public sealed class PathSecurity {
|
|
264
|
+
public RawSecurityDescriptor Descriptor;
|
|
265
|
+
public uint Attributes;
|
|
266
|
+
public string Capability;
|
|
267
|
+
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
|
|
268
|
+
static extern SafeFileHandle CreateFile(string name, uint access, uint share, IntPtr security, uint disposition, uint flags, IntPtr template);
|
|
269
|
+
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
|
|
270
|
+
static extern uint GetFinalPathNameByHandle(SafeFileHandle file, StringBuilder path, uint length, uint flags);
|
|
271
|
+
[DllImport("kernel32.dll", SetLastError=true)]
|
|
272
|
+
static extern bool GetFileInformationByHandleEx(SafeFileHandle file, int kind, out TagInfo info, uint size);
|
|
273
|
+
[DllImport("kernel32.dll")]
|
|
274
|
+
static extern uint GetFileType(SafeFileHandle file);
|
|
275
|
+
[StructLayout(LayoutKind.Sequential)] struct TagInfo { public uint Attributes; public uint Tag; }
|
|
276
|
+
[DllImport("advapi32.dll")]
|
|
277
|
+
static extern uint GetSecurityInfo(SafeFileHandle file, int kind, uint information, out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor);
|
|
278
|
+
[DllImport("advapi32.dll")]
|
|
279
|
+
static extern uint GetSecurityDescriptorLength(IntPtr descriptor);
|
|
280
|
+
[DllImport("kernel32.dll")]
|
|
281
|
+
static extern IntPtr LocalFree(IntPtr memory);
|
|
282
|
+
[DllImport("advapi32.dll")]
|
|
283
|
+
static extern IntPtr FreeSid(IntPtr sid);
|
|
284
|
+
[DllImport("userenv.dll", CharSet=CharSet.Unicode)]
|
|
285
|
+
static extern int DeriveAppContainerSidFromAppContainerName(string name, out IntPtr sid);
|
|
286
|
+
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
|
|
287
|
+
static extern int GetPackagesByPackageFamily(string family, ref uint count, IntPtr names, ref uint size, IntPtr buffer);
|
|
288
|
+
static SafeFileHandle Open(string file, uint access) {
|
|
289
|
+
var handle = CreateFile(file, access, 7, IntPtr.Zero, 3, 0x02200000, IntPtr.Zero);
|
|
290
|
+
if (handle.IsInvalid) { handle.Dispose(); throw new Win32Exception(); }
|
|
291
|
+
return handle;
|
|
292
|
+
}
|
|
293
|
+
static string Physical(SafeFileHandle handle) {
|
|
294
|
+
var path = new StringBuilder(32768);
|
|
295
|
+
uint length = GetFinalPathNameByHandle(handle, path, 32768, 0);
|
|
296
|
+
if (length == 0 || length >= 32768) throw new Win32Exception();
|
|
297
|
+
return path.ToString();
|
|
298
|
+
}
|
|
299
|
+
static string PackageCapability(string physical) {
|
|
300
|
+
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
|
301
|
+
string prefix;
|
|
302
|
+
using (var handle = Open(home, 0x80)) { prefix = Physical(handle).TrimEnd('\\') + @"\AppData\Local\Packages\"; }
|
|
303
|
+
if (!physical.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
|
|
304
|
+
string relative = physical.Substring(prefix.Length);
|
|
305
|
+
int end = relative.IndexOf('\\');
|
|
306
|
+
if (end <= 0 || end > 255) return null;
|
|
307
|
+
string family = relative.Substring(0, end), tail = relative.Substring(end);
|
|
308
|
+
const string npm = @"\LocalCache\Roaming\npm";
|
|
309
|
+
if (!tail.Equals(npm, StringComparison.OrdinalIgnoreCase) && !tail.StartsWith(npm + @"\", StringComparison.OrdinalIgnoreCase)) return null;
|
|
310
|
+
uint count = 0, size = 0;
|
|
311
|
+
if (GetPackagesByPackageFamily(family, ref count, IntPtr.Zero, ref size, IntPtr.Zero) != 122 || count == 0 || size == 0) return null;
|
|
312
|
+
IntPtr pointer;
|
|
313
|
+
if (DeriveAppContainerSidFromAppContainerName(family, out pointer) != 0) return null;
|
|
314
|
+
try {
|
|
315
|
+
var sid = new SecurityIdentifier(pointer);
|
|
316
|
+
byte[] bytes = new byte[sid.BinaryLength]; sid.GetBinaryForm(bytes, 0);
|
|
317
|
+
if (bytes.Length != 40 || bytes[1] != 8 || BitConverter.ToUInt32(bytes, 8) != 2) return null;
|
|
318
|
+
bytes[8] = 3;
|
|
319
|
+
return new SecurityIdentifier(bytes, 0).Value;
|
|
320
|
+
} finally { FreeSid(pointer); }
|
|
321
|
+
}
|
|
322
|
+
public static PathSecurity Read(string file, bool package) {
|
|
323
|
+
using (var handle = Open(file, 0x20080)) {
|
|
324
|
+
TagInfo info;
|
|
325
|
+
if (GetFileType(handle) != 1 || !GetFileInformationByHandleEx(handle, 9, out info, 8) || (info.Attributes & 0x400) != 0) throw new IOException("Existing path is linked or not a disk object");
|
|
326
|
+
IntPtr owner, group, dacl, sacl, descriptor;
|
|
327
|
+
uint error = GetSecurityInfo(handle, 1, 5, out owner, out group, out dacl, out sacl, out descriptor);
|
|
328
|
+
if (error != 0) throw new Win32Exception((int)error);
|
|
329
|
+
try {
|
|
330
|
+
uint length = GetSecurityDescriptorLength(descriptor);
|
|
331
|
+
if (length == 0 || length > 1024 * 1024) throw new IOException("Invalid path security descriptor");
|
|
332
|
+
byte[] bytes = new byte[length]; Marshal.Copy(descriptor, bytes, 0, bytes.Length);
|
|
333
|
+
return new PathSecurity { Descriptor = new RawSecurityDescriptor(bytes, 0), Attributes = info.Attributes,
|
|
334
|
+
Capability = package ? PackageCapability(Physical(handle)) : null };
|
|
335
|
+
} finally { LocalFree(descriptor); }
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
'@
|
|
341
|
+
}
|
|
342
|
+
return [NotifaiBootstrap.PathSecurity]::Read($File, $Package)
|
|
343
|
+
}
|
|
218
344
|
# Read-only inspection of an existing path. npm can inherit a token's default
|
|
219
345
|
# owner. The OS-confirmed profile can belong to Windows itself; this exception
|
|
220
346
|
# must never admit a system-owned npm package or managed installation path.
|
|
221
347
|
function Assert-NotifaiPathAccess([string]$File, [switch]$AllowDefaultOwner, [switch]$RequireProtected, [switch]$AccountHome) {
|
|
222
348
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
223
349
|
$user = $identity.User.Value
|
|
224
|
-
$
|
|
225
|
-
$
|
|
226
|
-
$
|
|
350
|
+
$security = Get-NotifaiPathSecurity $File $AllowDefaultOwner
|
|
351
|
+
$attributes = [IO.FileAttributes]$security.Attributes
|
|
352
|
+
$acl = $security.Descriptor
|
|
353
|
+
if ($null -eq $acl.Owner -or $null -eq $acl.DiscretionaryAcl) { throw 'Existing path has no owner or discretionary access control' }
|
|
354
|
+
$owner = $acl.Owner.Value
|
|
227
355
|
$defaultOwner = $AllowDefaultOwner -and $identity.Owner.Value -eq 'S-1-5-32-544' -and $owner -eq $identity.Owner.Value
|
|
228
356
|
$profileOwner = $false
|
|
229
357
|
if ($AccountHome) {
|
|
@@ -234,12 +362,13 @@ function Assert-NotifaiPathAccess([string]$File, [switch]$AllowDefaultOwner, [sw
|
|
|
234
362
|
}
|
|
235
363
|
if (($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
|
|
236
364
|
($owner -ne $user -and -not $defaultOwner -and -not $profileOwner) -or
|
|
237
|
-
($RequireProtected -and
|
|
365
|
+
($RequireProtected -and ($acl.ControlFlags -band [Security.AccessControl.ControlFlags]::DiscretionaryAclProtected) -eq 0)) { throw 'Existing path is not privately owned; inspect it before repair' }
|
|
238
366
|
$writes = [int64][Security.AccessControl.FileSystemRights]'Write, Delete, DeleteSubdirectoriesAndFiles, ChangePermissions, TakeOwnership' -bor 0x50000000
|
|
239
|
-
foreach ($rule in $acl.
|
|
240
|
-
if ($rule.
|
|
241
|
-
|
|
242
|
-
|
|
367
|
+
foreach ($rule in $acl.DiscretionaryAcl) {
|
|
368
|
+
if ($rule.AceType -eq [Security.AccessControl.AceType]::AccessDenied) { continue }
|
|
369
|
+
if ($rule.AceType -ne [Security.AccessControl.AceType]::AccessAllowed) { throw 'Existing path has unsupported access rules' }
|
|
370
|
+
if (([int64]$rule.AccessMask -band $writes) -ne 0 -and
|
|
371
|
+
$rule.SecurityIdentifier.Value -notin @($user, 'S-1-5-18', 'S-1-5-32-544', $security.Capability)) { throw 'Existing path permits another writer; inspect it before repair' }
|
|
243
372
|
}
|
|
244
373
|
}
|
|
245
374
|
function Get-NotifaiInstalledCommand {
|
|
@@ -264,13 +393,15 @@ function Get-NotifaiInstallArguments {
|
|
|
264
393
|
if ($NoInit) { $nativeArgs += '--no-init' }
|
|
265
394
|
if ($NoPath) { $nativeArgs += '--no-path' }
|
|
266
395
|
if ($MigrateNpm) { $nativeArgs += '--migrate-npm' }
|
|
396
|
+
if ($Upgrade) { $nativeArgs += '--upgrade' }
|
|
267
397
|
return $nativeArgs
|
|
268
398
|
}
|
|
269
399
|
function Invoke-NotifaiBootstrap {
|
|
270
400
|
$selectedChannel = if ($Channel) { $Channel } else { 'stable' }
|
|
271
401
|
if ($Version -and -not (Test-NotifaiVersion $Version)) { throw 'Version must be an exact semantic version' }
|
|
402
|
+
if ($Upgrade -and (-not $Version -or -not $Channel -or -not $NoInit -or -not $NoPath)) { throw 'Upgrade requires exact version, channel, no-init and no-path' }
|
|
272
403
|
$existing = Get-NotifaiInstalledCommand
|
|
273
|
-
if ($existing) {
|
|
404
|
+
if ($existing -and -not $Upgrade) {
|
|
274
405
|
Invoke-NotifaiCandidate $existing (Get-NotifaiInstallArguments)
|
|
275
406
|
return
|
|
276
407
|
}
|
package/data/release.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"12.0.0
|
|
1
|
+
{"version":"12.0.0","source_revision":"589d4598accb04d83e740868badcae32a3038f28"}
|
package/inventory.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"key_id":"notifai-release-2026-10","payload":"eyJzY2hlbWEiOjEsInZlcnNpb24iOiIxMi4wLjAtYmV0YS42Iiwic291cmNlX3JldmlzaW9uIjoiMzdkMTAxNjQ2Y2ZhMTI4NWRhOTM1ODEzNTcyNDRmMTBkNzljYTI5NyIsInN0b3JlX3NjaGVtYSI6MSwibGF1bmNoZXJfc2NoZW1hIjoxLCJhcnRpZmFjdHMiOlt7InRhcmdldCI6ImJ1bi1kYXJ3aW4tYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuNi1kYXJ3aW4tYXJtNjQudGFyLmd6IiwiYnl0ZXMiOjI3NzY0MDY4LCJzaGEyNTYiOiI5ZWVjMTg2NTM3MjEzODkxYTY0NGQ1NjM0MGIwMDQ5OTI5NGNkNDE4OTIyYmQyMjM1YzM2YjQwMGM1OTc5YzhlIiwicnVudGltZV9zaGEyNTYiOiI5MzY3MDdlYjI4NDU4ODMzMTZlOTI2NTEzYTlmODc0ZjFlYTMxNmQxYTMyYjViMzljYTYwNTAwOTY3MjQzMTlhIiwibGF1bmNoZXJfc2hhMjU2IjoiZjczZTg2MTE4MGYwNDhmYjQ4ZWQyMjk5YWZkODVkZjU2ZGM3MjlmYjAwN2U4YjBjYjRkZmJjYWUxYTJiZDUwYiIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MjEsInNoYTI1NiI6IjgyZDg1ZWRhODc1MzVlYzQyMzQyZWI3ZTNiZjc3NGM1OTVhNTJmNjU2MWQyYTczZjY1YWVkOTFiYzMxOGU1MzgifV19LHsidGFyZ2V0IjoiYnVuLWRhcndpbi14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuNi1kYXJ3aW4teDY0LnRhci5neiIsImJ5dGVzIjozMDAwMTExNCwic2hhMjU2IjoiMzg0NDc0NDVjYjFmNzVmZGNkMmUwNDgwZmFiN2Y4ZjljZjQyZDU4YjU3ZDU4MzJjOWJkNjQ0NzlkOWFlNjBjMyIsInJ1bnRpbWVfc2hhMjU2IjoiODEwOTFhZjI5OTNjYjZjZjVlZDcwYzk0YTQ4MTFmY2RhZGFjNjYzOWM2MjY3N2M3YWY1NGY0MDdiZTcyNzcxMCIsImxhdW5jaGVyX3NoYTI1NiI6IjgwNzViZDgwMzJjNTJjMjY1ZTQ2YzEyZWVjYmRhMzdiYzkzNWQ1ZjUwNmVjMDgzZGVmN2Q3MzZkZDQ3YTQ5ZTQiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiI4MmQ4NWVkYTg3NTM1ZWM0MjM0MmViN2UzYmY3NzRjNTk1YTUyZjY1NjFkMmE3M2Y2NWFlZDkxYmMzMThlNTM4In1dfSx7InRhcmdldCI6ImJ1bi1saW51eC1hcm02NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS42LWxpbnV4LWFybTY0LnRhci5neiIsImJ5dGVzIjozOTMxMTg5Niwic2hhMjU2IjoiYjQxZjE3MDZlOTgwMmE0YjA5YzNiMTc2MmNlOWZkZTBhNjAxN2Y2ZTcwNzY4ZDM2MzQzNGZjZWFlZDhjNzU1ZiIsInJ1bnRpbWVfc2hhMjU2IjoiNjNhY2NmMjRmZWE3YWNmY2UyNzU0YTJjNjhlZDgwNjBlMWY1NDE0ODFiZGU5YjJmZGQ4ZDkzZDk4ZGM5NDAxZSIsImxhdW5jaGVyX3NoYTI1NiI6ImMxOWUzMzJjODIxYjcxMjhjYjI1ZjYxZTRhYjdlMGIzYzYzMzQ1ZjA0ZTJhYjVhYjk1ZDQ1MWE0YTZmYmRjNDUiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiI4MmQ4NWVkYTg3NTM1ZWM0MjM0MmViN2UzYmY3NzRjNTk1YTUyZjY1NjFkMmE3M2Y2NWFlZDkxYmMzMThlNTM4In1dfSx7InRhcmdldCI6ImJ1bi1saW51eC14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuNi1saW51eC14NjQudGFyLmd6IiwiYnl0ZXMiOjM4ODc1MzU5LCJzaGEyNTYiOiJjNjgzNGUyMGZkMzY2Y2IzYjQxNWQ5OTA1MDRkZTliODYwN2YzOTBhZWUxZWZkNzA5NzBhODdjNTY1MjBkYzRjIiwicnVudGltZV9zaGEyNTYiOiIxODRiZWRkZTc4OTJiOGI5ZGFjMTUwOTE3M2I5ZjZjZTE3NTYwMDEyOWRiYWIwNTBkNWU0ZDNhYzY3YmJiMjU2IiwibGF1bmNoZXJfc2hhMjU2IjoiYmRmOGQ0N2RmODU4MWFjZTI5YjU3OTA0NTdjYmM2YzI2ZDEyYjNjYjE0YzBkZGFiMzM3OWE3Mjc1ZDllYTRiMSIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MjEsInNoYTI1NiI6IjgyZDg1ZWRhODc1MzVlYzQyMzQyZWI3ZTNiZjc3NGM1OTVhNTJmNjU2MWQyYTczZjY1YWVkOTFiYzMxOGU1MzgifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MtYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuNi13aW5kb3dzLWFybTY0LnppcCIsImJ5dGVzIjozODcwNjAzNiwic2hhMjU2IjoiYzIyM2IxZjEyNDk1YzM5MTkyZDQ2NmI3NDgwMDYwNGJkZDA2MTFhZmZjNDA5Zjc3MTcwY2FmZWJkZTQzN2FhNCIsInJ1bnRpbWVfc2hhMjU2IjoiZDFhZTBhYTliYTNkZWQwYzhkOTk3NDMzNGFiN2ZhYzdjMGJkZDA3YTZlNzBhNDcwZTM2ZWYzZmJmNWZhZDk5OSIsImxhdW5jaGVyX3NoYTI1NiI6ImM0ZTkyM2Q4ZWIzMjM3YjkzM2M4MjMxMDNmYzU5MDFmYjcxMDhmOTMwZjc4ZjI2ZDlhMTNiYjhiZThmMTk3ZTgiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiI4MmQ4NWVkYTg3NTM1ZWM0MjM0MmViN2UzYmY3NzRjNTk1YTUyZjY1NjFkMmE3M2Y2NWFlZDkxYmMzMThlNTM4In1dfSx7InRhcmdldCI6ImJ1bi13aW5kb3dzLXg2NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS42LXdpbmRvd3MteDY0LnppcCIsImJ5dGVzIjo0MTg1MTg1Niwic2hhMjU2IjoiZWM4YWI0ZTE0YzZjYjc3NTZhYjEwZTg4MmY3YzMwYTFkYjMxMDYyZThlYzdkNzMxN2M2NTU5NTk5ZDg1Mzc5NiIsInJ1bnRpbWVfc2hhMjU2IjoiYzNlYmRlNjhiNjVlYTYyOWM2N2Y5ZmQ4ZTdmMTlmY2U3YzYwZmQwZmU1M2IwNTdhMjgzYmNkMGU3NzVlNGE3NyIsImxhdW5jaGVyX3NoYTI1NiI6IjViOGM0ZWNlYjNjYjEwOWQ5MzlkNzVkZTkwYWZjODZiOWViZGRiNzA0Yzc0ZmE2YmM3ZGJjMWY0NjYxMTcyZTgiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiI4MmQ4NWVkYTg3NTM1ZWM0MjM0MmViN2UzYmY3NzRjNTk1YTUyZjY1NjFkMmE3M2Y2NWFlZDkxYmMzMThlNTM4In1dfV19","signature":"MsTGT7wSxNhW7BoQ9NtqzQZpC+zE+/iHFTVQcwzQ3D6VDzSZaYSmIuzFPSzFq9dX1hAoip7JnpQEYkPKZKF7DA=="}
|
|
1
|
+
{"key_id":"notifai-release-2026-10","payload":"eyJzY2hlbWEiOjIsInZlcnNpb24iOiIxMi4wLjAiLCJzb3VyY2VfcmV2aXNpb24iOiI1ODlkNDU5OGFjY2IwNGQ4M2U3NDA4NjhiYWRjYWUzMmEzMDM4ZjI4IiwibG9jYWxfY29udGludWl0eSI6eyJjb250cmFjdCI6Im5vdGlmYWktc2Vzc2lvbi1zdGF0ZS12MiJ9LCJzdG9yZV9zY2hlbWEiOjIsImxhdW5jaGVyX3NjaGVtYSI6MSwiYXJ0aWZhY3RzIjpbeyJ0YXJnZXQiOiJidW4tZGFyd2luLWFybTY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1kYXJ3aW4tYXJtNjQudGFyLmd6IiwiYnl0ZXMiOjI3ODM0MzUzLCJzaGEyNTYiOiIwZTdmOTY2ZjE1MDI0OTkzMDM3YjUyM2I4M2QxMTQzZDFlYzA3NjAyNGZlMjE0YzUxZTg1ZTFhN2RhMzJmNzEzIiwicnVudGltZV9zaGEyNTYiOiJlMWVlNDkzNjU4Y2M2M2IxZjJlMmJlMWQ2ZGVkNzY0ZjYyNWM2Y2FiYTIzZDBhYTg1MGIwZDg3OGExYTRhOWYwIiwibGF1bmNoZXJfc2hhMjU2IjoiMjE3YjQ1OGU4NGQ0ZmUzNzM2YzkzMDIyN2NlZTY5YjZiYmM2ZDJiNzQzYmI1MDBlZDAwODZiNmQ1ZGMzZjg4ZCIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLWRhcndpbi14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWRhcndpbi14NjQudGFyLmd6IiwiYnl0ZXMiOjMwMDczNjEzLCJzaGEyNTYiOiJmMmNkNDdhZTIxYmFhZTIxOGM0N2Y0NDdjZmFjZTM4OTBlMmJmMzFlYTI1YjIxNTc1N2JhYTk3MjJkNGM5NzdjIiwicnVudGltZV9zaGEyNTYiOiIxM2U5MWFkZDQ4OTJlMjQ4OTg1MDExZTdmMWM3OWMwODFmOWJjN2EwNmI0ZTc3YjI5ODhjMjQwOTcyMzg1MTAyIiwibGF1bmNoZXJfc2hhMjU2IjoiNDg1OGY0MmYwNjM5NGM5NmZlODY1OWFhNmMyNmYwZTkzNTgxYjQ3NjhjNTMzZTI1Y2M1MDFhYjViZTVjNDQyZSIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLWxpbnV4LWFybTY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1saW51eC1hcm02NC50YXIuZ3oiLCJieXRlcyI6MzkzNzg5MzIsInNoYTI1NiI6ImJhOTUyZjdlY2RmZTUxYWMwMTE0Nzk3MGY5MDkyZGE5NDE3Y2QyYjA1Y2RiZWNmOTI3OGIzN2YxN2Y3ZjczYmQiLCJydW50aW1lX3NoYTI1NiI6IjkyMmFkMGM4ZWFkOTNiMWQ3ODdhYzQ1NDhjZDU1ZjkyNzkyZjA2YjI3N2U1NGIwYTBmZTMyNmRmNTlmYzM1NGQiLCJsYXVuY2hlcl9zaGEyNTYiOiJmODBmZGJmMzNmYmFhMzkwM2M1NDUyNmYxOTU2YzYxOWYyZjQ3MDFmOTg3MTkwYzViYTJiNGQ1NzRiNDMxMGE0IiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUwMCwic2hhMjU2IjoiNjM1YjQyNjc5MzVlMjlkYzg4MzBjMjBiMTRmZmQxMTk0YzY0MjBkNjFlYWYxMTI1NzQzMjc2NGE1ODQ5MTFjZiJ9XX0seyJ0YXJnZXQiOiJidW4tbGludXgteDY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1saW51eC14NjQudGFyLmd6IiwiYnl0ZXMiOjM4OTQzNzkzLCJzaGEyNTYiOiIxMmM1M2MyODIzZjlhZGYxNzI5NmZkOWQ2MGZhZmEzOTk4YmIwZWU1YTdiOGZiMTg2OGFiN2I2ZDEwZTNmMTY2IiwicnVudGltZV9zaGEyNTYiOiI2ZGMyOTYxMmVhYThkYWY1NzhhZjI2NWEyODJmN2I3MDJmNmQ0Y2M2ZDcwY2ViYjJlNDFjYzRjNjlmM2RmZGFkIiwibGF1bmNoZXJfc2hhMjU2IjoiOGIxZjA5M2U0NGM2ZmQzOTg0MWUzOWJkZTk3YjI3MTUwNDhkMzk2M2I3MDRmNjJmMmFiZWI1OTAyYzdmYmJlNyIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MtYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLXdpbmRvd3MtYXJtNjQuemlwIiwiYnl0ZXMiOjM4Nzc2MDA3LCJzaGEyNTYiOiI5YWIzMmI0Y2ZlNTM4OWZmZTcxYjZmY2M1YmY3MjNkNzVjMGM2ZGU3OTQwNGZiYWE1NmJiZWQwMDEyOTk5NWY2IiwicnVudGltZV9zaGEyNTYiOiI1YTRmM2I5OTYxZmEwY2ViMjVhZDhhY2E2MGQ3NWVhOTc1YjAyZmQyZThmMDExZTUyY2QzNWE3ZDA4NDNmYjhkIiwibGF1bmNoZXJfc2hhMjU2IjoiNzBjMGJiMjAxYzlkY2RiYTYwNWQwOWI2MGE1YjQ5ZjcxOWQ1YTg1MDRjMDZhYzViNjNjNDNlNzFiMzYzMjM3ZiIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MteDY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC13aW5kb3dzLXg2NC56aXAiLCJieXRlcyI6NDE5MjIyNjIsInNoYTI1NiI6ImRiMjQ4NTU5YjRhNTY0NDQxZjkxNDlkYTc5YzNhNzRlZDU5ODRjZjc1ZDJhOWJjYjk3MTUzNjllYWYzZjQ4NDEiLCJydW50aW1lX3NoYTI1NiI6IjE2ZThiMTdlMDFmYzUxNTYwY2Q4MjU4MWY0MjQ1ZjdhMDM5OGE1MTc5MTZlZmMxMjM2NDViYTFmOTMyN2FjMGMiLCJsYXVuY2hlcl9zaGEyNTYiOiIzN2NlYzMwM2NlZmEzMWE2N2ViOTRhMzMwNjE4ZTBkYTFiNDIyZTcxZWI1ZGM5OTY1NWZiMmIyNzBlYWI5NWFkIiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUwMCwic2hhMjU2IjoiNjM1YjQyNjc5MzVlMjlkYzg4MzBjMjBiMTRmZmQxMTk0YzY0MjBkNjFlYWYxMTI1NzQzMjc2NGE1ODQ5MTFjZiJ9XX1dfQ==","signature":"AhZTM63Se5CnP2qeVMCEYyHnHSVMiKmkXVDVUCVBOgEOntT596bL696RipGFIZHUK5JAD6TNMSBQToDqftkxAA=="}
|
package/npm-adapter-files.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"package": "@raidiant/notifai",
|
|
4
|
-
"adapter_version": "12.0.0
|
|
4
|
+
"adapter_version": "12.0.0",
|
|
5
5
|
"native": {
|
|
6
|
-
"version": "12.0.0
|
|
7
|
-
"source_revision": "
|
|
8
|
-
"inventory_url": "https://github.com/Raidiant-io/notifai/releases/download/v12.0.0
|
|
6
|
+
"version": "12.0.0",
|
|
7
|
+
"source_revision": "589d4598accb04d83e740868badcae32a3038f28",
|
|
8
|
+
"inventory_url": "https://github.com/Raidiant-io/notifai/releases/download/v12.0.0/inventory.json"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
{
|
|
12
12
|
"path": "CHANGELOG.md",
|
|
13
|
-
"bytes":
|
|
14
|
-
"sha256": "
|
|
13
|
+
"bytes": 62276,
|
|
14
|
+
"sha256": "1a7f2dbdab467c6db132fad3dd62e88647f8d19291f7577ee7ceb403c95a69d7"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"path": "LICENSE",
|
|
@@ -30,23 +30,23 @@
|
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "bin/notifai.mjs",
|
|
33
|
-
"bytes":
|
|
34
|
-
"sha256": "
|
|
33
|
+
"bytes": 521624,
|
|
34
|
+
"sha256": "ef90a76ffa8081d21f7e496f904e20aed391c99be78e06382137dfe19eaddf49"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"path": "data/install.ps1",
|
|
38
|
-
"bytes":
|
|
39
|
-
"sha256": "
|
|
38
|
+
"bytes": 26228,
|
|
39
|
+
"sha256": "e111259532c11e1e822356d34b0b30059db17b59e6b69ce3af74e491ee3cbc5a"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"path": "data/release.json",
|
|
43
|
-
"bytes":
|
|
44
|
-
"sha256": "
|
|
43
|
+
"bytes": 82,
|
|
44
|
+
"sha256": "4e070f976fbe30a96ae78e48faec259c7c0119fea3eccd6a63e5582a04442c84"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"path": "package.json",
|
|
48
|
-
"bytes":
|
|
49
|
-
"sha256": "
|
|
48
|
+
"bytes": 807,
|
|
49
|
+
"sha256": "81a9d0c23154484501ad1b7f47325ae636d6e219768b2156ef195a035e6408eb"
|
|
50
50
|
}
|
|
51
51
|
]
|
|
52
52
|
}
|