@goliapkg/sentori-cli 0.5.3 → 1.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/README.md +27 -32
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +723 -0
- package/lib/index.js.map +1 -0
- package/lib/issue.d.ts +26 -0
- package/lib/issue.d.ts.map +1 -0
- package/lib/issue.js +50 -0
- package/lib/issue.js.map +1 -0
- package/lib/lenient.d.ts +13 -0
- package/lib/lenient.d.ts.map +1 -0
- package/lib/lenient.js +25 -0
- package/lib/lenient.js.map +1 -0
- package/lib/mcp.d.ts +16 -0
- package/lib/mcp.d.ts.map +1 -0
- package/lib/mcp.js +194 -0
- package/lib/mcp.js.map +1 -0
- package/lib/native-artifacts.d.ts +42 -0
- package/lib/native-artifacts.d.ts.map +1 -0
- package/lib/native-artifacts.js +137 -0
- package/lib/native-artifacts.js.map +1 -0
- package/lib/probes.d.ts +10 -0
- package/lib/probes.d.ts.map +1 -0
- package/lib/probes.js +75 -0
- package/lib/probes.js.map +1 -0
- package/lib/push.d.ts +42 -0
- package/lib/push.d.ts.map +1 -0
- package/lib/push.js +92 -0
- package/lib/push.js.map +1 -0
- package/lib/react-native.d.ts +25 -0
- package/lib/react-native.d.ts.map +1 -0
- package/lib/react-native.js +82 -0
- package/lib/react-native.js.map +1 -0
- package/lib/source-bundle.d.ts +28 -0
- package/lib/source-bundle.d.ts.map +1 -0
- package/lib/source-bundle.js +193 -0
- package/lib/source-bundle.js.map +1 -0
- package/lib/upload.d.ts +13 -0
- package/lib/upload.d.ts.map +1 -0
- package/lib/upload.js +28 -0
- package/lib/upload.js.map +1 -0
- package/package.json +23 -13
- package/src/__tests__/lenient.test.ts +32 -0
- package/src/__tests__/mcp.test.ts +32 -0
- package/src/__tests__/native-artifacts.test.ts +125 -0
- package/src/__tests__/probes.test.ts +41 -0
- package/src/__tests__/react-native.test.ts +37 -0
- package/src/index.ts +727 -0
- package/src/issue.ts +82 -0
- package/src/lenient.ts +39 -0
- package/src/mcp.ts +230 -0
- package/src/native-artifacts.ts +175 -0
- package/src/probes.ts +75 -0
- package/src/push.ts +174 -0
- package/src/react-native.ts +94 -0
- package/src/upload.ts +44 -0
- package/bin/sentori-cli.js +0 -32
- package/scripts/postinstall.js +0 -90
package/lib/probes.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// `sentori-cli probes sync` — the tripwire registry scan
|
|
2
|
+
// (design.md §2). Statically scans source for `sentori.probe('REF')`
|
|
3
|
+
// / `probe("REF")` call sites and registers the refs against a
|
|
4
|
+
// release, so the server can tell a silent probe (fix holding) from
|
|
5
|
+
// deleted code.
|
|
6
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
const PROBE_RE = /\bprobe\(\s*['"`]([^'"`]{1,200})['"`]/g;
|
|
9
|
+
const SCAN_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
10
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'lib', 'dist', 'build', '.expo']);
|
|
11
|
+
const MAX_FILES = 20_000;
|
|
12
|
+
export function scanProbes(root) {
|
|
13
|
+
const refs = new Set();
|
|
14
|
+
let seen = 0;
|
|
15
|
+
const walk = (dir) => {
|
|
16
|
+
if (seen > MAX_FILES)
|
|
17
|
+
return;
|
|
18
|
+
let entries;
|
|
19
|
+
try {
|
|
20
|
+
entries = readdirSync(dir);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const name of entries) {
|
|
26
|
+
if (SKIP_DIRS.has(name))
|
|
27
|
+
continue;
|
|
28
|
+
const p = join(dir, name);
|
|
29
|
+
let st;
|
|
30
|
+
try {
|
|
31
|
+
st = statSync(p);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (st.isDirectory()) {
|
|
37
|
+
walk(p);
|
|
38
|
+
}
|
|
39
|
+
else if (st.isFile()) {
|
|
40
|
+
const dot = name.lastIndexOf('.');
|
|
41
|
+
if (dot === -1 || !SCAN_EXTS.has(name.slice(dot)))
|
|
42
|
+
continue;
|
|
43
|
+
seen += 1;
|
|
44
|
+
try {
|
|
45
|
+
const text = readFileSync(p, 'utf8');
|
|
46
|
+
for (const m of text.matchAll(PROBE_RE)) {
|
|
47
|
+
const ref = m[1];
|
|
48
|
+
if (ref)
|
|
49
|
+
refs.add(ref);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// unreadable file — skip
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
walk(root);
|
|
59
|
+
return [...refs].sort();
|
|
60
|
+
}
|
|
61
|
+
export async function syncProbes(opts) {
|
|
62
|
+
const resp = await fetch(`${opts.apiUrl.replace(/\/+$/, '')}/api/probes:sync`, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
Authorization: `Bearer ${opts.token}`,
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify({ release: opts.release, refs: opts.refs }),
|
|
69
|
+
});
|
|
70
|
+
if (!resp.ok) {
|
|
71
|
+
throw new Error(`probes:sync ${resp.status} ${await resp.text().catch(() => '')}`);
|
|
72
|
+
}
|
|
73
|
+
return (await resp.json());
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=probes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probes.js","sourceRoot":"","sources":["../src/probes.ts"],"names":[],"mappings":"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"}
|
package/lib/push.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type PushClientConfig = {
|
|
2
|
+
apiUrl: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
token: string;
|
|
5
|
+
};
|
|
6
|
+
type AdminCredentialRow = {
|
|
7
|
+
provider: string;
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
};
|
|
11
|
+
type Ticket = {
|
|
12
|
+
id: string;
|
|
13
|
+
status: 'queued' | 'sent' | 'failed';
|
|
14
|
+
providerOutcome?: string | null;
|
|
15
|
+
error?: string | null;
|
|
16
|
+
retryCount: number;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
sentAt?: string | null;
|
|
19
|
+
};
|
|
20
|
+
/** Parse a CLI flag value that may be `@file.json` (read from disk
|
|
21
|
+
* and parse) or a literal JSON string. */
|
|
22
|
+
export declare function parseJsonArg(raw: string, kind: string): unknown;
|
|
23
|
+
export declare function pushCredsList(cfg: PushClientConfig): Promise<AdminCredentialRow[]>;
|
|
24
|
+
export declare function pushCredsSet(cfg: PushClientConfig, provider: string, config: unknown, secret: unknown): Promise<{
|
|
25
|
+
ok: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function pushCredsDelete(cfg: PushClientConfig, provider: string): Promise<void>;
|
|
28
|
+
export type SendOpts = {
|
|
29
|
+
to: string;
|
|
30
|
+
title?: string;
|
|
31
|
+
body?: string;
|
|
32
|
+
data?: unknown;
|
|
33
|
+
priority?: 'high' | 'normal';
|
|
34
|
+
ttl?: number;
|
|
35
|
+
idempotencyKey?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function pushSend(cfg: PushClientConfig, opts: SendOpts): Promise<Ticket>;
|
|
38
|
+
export declare function pushReceipt(cfg: PushClientConfig, sendId: string): Promise<{
|
|
39
|
+
ticket: Ticket;
|
|
40
|
+
}>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,MAAM,GAAG;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;IACpC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AA+BD;2CAC2C;AAC3C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAe/D;AAID,wBAAsB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAKxF;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC,CAc1B;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CASf;AAID,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBrF;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,gBAAgB,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7B"}
|
package/lib/push.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// v2.12 — `sentori-cli push *` commands.
|
|
2
|
+
//
|
|
3
|
+
// Wraps the v2.7 admin REST + v2.7 ingest endpoints so operators can
|
|
4
|
+
// drive credential CRUD, ad-hoc sends, and receipt lookups from the
|
|
5
|
+
// terminal without touching curl.
|
|
6
|
+
//
|
|
7
|
+
// `push send` POST /v1/push/send (ingest Bearer)
|
|
8
|
+
// `push receipt` GET /v1/push/receipts/:id (ingest Bearer)
|
|
9
|
+
// `push creds list` GET /admin/api/projects/:id/push/credentials (admin Bearer)
|
|
10
|
+
// `push creds set` PUT /admin/api/projects/:id/push/credentials (admin Bearer)
|
|
11
|
+
// `push creds delete` DELETE /admin/api/projects/:id/push/credentials/:provider
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
const VALID_PROVIDERS = new Set(['apns', 'fcm', 'webpush', 'hcm', 'mipush']);
|
|
14
|
+
function joinUrl(base, path) {
|
|
15
|
+
return `${base.replace(/\/+$/, '')}${path}`;
|
|
16
|
+
}
|
|
17
|
+
async function bearerFetch(url, token, init) {
|
|
18
|
+
const resp = await fetch(url, {
|
|
19
|
+
...init,
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${token}`,
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
...(init?.headers ?? {}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
if (!resp.ok) {
|
|
27
|
+
const detail = await resp.text().catch(() => '');
|
|
28
|
+
throw new Error(`${resp.status} ${resp.statusText}${detail ? ` — ${detail.slice(0, 300)}` : ''}`);
|
|
29
|
+
}
|
|
30
|
+
const txt = await resp.text();
|
|
31
|
+
return (txt ? JSON.parse(txt) : null);
|
|
32
|
+
}
|
|
33
|
+
/** Parse a CLI flag value that may be `@file.json` (read from disk
|
|
34
|
+
* and parse) or a literal JSON string. */
|
|
35
|
+
export function parseJsonArg(raw, kind) {
|
|
36
|
+
if (raw.startsWith('@')) {
|
|
37
|
+
const path = raw.slice(1);
|
|
38
|
+
const body = readFileSync(path, 'utf-8');
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(body);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
throw new Error(`${kind} file ${path} is not valid JSON: ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
throw new Error(`${kind} arg is not valid JSON: ${e.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// ── credential CRUD ───────────────────────────────────────────────
|
|
54
|
+
export async function pushCredsList(cfg) {
|
|
55
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials`), cfg.token);
|
|
56
|
+
}
|
|
57
|
+
export async function pushCredsSet(cfg, provider, config, secret) {
|
|
58
|
+
if (!VALID_PROVIDERS.has(provider)) {
|
|
59
|
+
throw new Error(`invalid provider '${provider}'; expected one of ${[...VALID_PROVIDERS].join('/')}`);
|
|
60
|
+
}
|
|
61
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials`), cfg.token, {
|
|
62
|
+
body: JSON.stringify({ provider, config, secret }),
|
|
63
|
+
method: 'PUT',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export async function pushCredsDelete(cfg, provider) {
|
|
67
|
+
await bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials/${provider}`), cfg.token, { method: 'DELETE' });
|
|
68
|
+
}
|
|
69
|
+
export async function pushSend(cfg, opts) {
|
|
70
|
+
const payload = {
|
|
71
|
+
to: opts.to,
|
|
72
|
+
title: opts.title,
|
|
73
|
+
body: opts.body,
|
|
74
|
+
data: opts.data,
|
|
75
|
+
idempotencyKey: opts.idempotencyKey,
|
|
76
|
+
};
|
|
77
|
+
if (opts.priority || opts.ttl != null) {
|
|
78
|
+
payload.options = { priority: opts.priority, ttl: opts.ttl };
|
|
79
|
+
}
|
|
80
|
+
const resp = await bearerFetch(joinUrl(cfg.apiUrl, '/v1/push/send'), cfg.token, {
|
|
81
|
+
body: JSON.stringify(payload),
|
|
82
|
+
method: 'POST',
|
|
83
|
+
});
|
|
84
|
+
if (!resp.tickets?.length) {
|
|
85
|
+
throw new Error('server returned no tickets');
|
|
86
|
+
}
|
|
87
|
+
return resp.tickets[0];
|
|
88
|
+
}
|
|
89
|
+
export async function pushReceipt(cfg, sendId) {
|
|
90
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/v1/push/receipts/${encodeURIComponent(sendId)}`), cfg.token);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=push.js.map
|
package/lib/push.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Resolve `react-native/scripts/compose-source-maps.js` from the
|
|
2
|
+
* current project's node_modules. Returns null if react-native isn't
|
|
3
|
+
* installed or the version doesn't ship that script. */
|
|
4
|
+
export declare function resolveComposeScript(fromDir?: string): null | string;
|
|
5
|
+
/** Compose a Metro packager source map + a Hermes source map into a
|
|
6
|
+
* single map (a temp file the caller is responsible for deleting).
|
|
7
|
+
* Throws if react-native's compose script can't be found or fails. */
|
|
8
|
+
export declare function composeSourceMaps(metroMap: string, hermesMap: string): string;
|
|
9
|
+
export type RnUploadOptions = {
|
|
10
|
+
apiUrl: string;
|
|
11
|
+
/** Optional bundle file (.jsbundle / .bundle) to upload alongside the map. */
|
|
12
|
+
bundle?: string;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
hermesMap: string;
|
|
15
|
+
metroMap: string;
|
|
16
|
+
release: string;
|
|
17
|
+
token: string;
|
|
18
|
+
};
|
|
19
|
+
/** Compose the Metro + Hermes maps, then upload the result (and the
|
|
20
|
+
* bundle, if given). Cleans up the temp composed map. */
|
|
21
|
+
export declare function reactNativeUpload(opts: RnUploadOptions): Promise<{
|
|
22
|
+
files: string[];
|
|
23
|
+
uploaded?: number;
|
|
24
|
+
}>;
|
|
25
|
+
//# sourceMappingURL=react-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../src/react-native.ts"],"names":[],"mappings":"AASA;;yDAEyD;AACzD,wBAAgB,oBAAoB,CAAC,OAAO,SAAgB,GAAG,IAAI,GAAG,MAAM,CAc3E;AAED;;uEAEuE;AACvE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkB7E;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;0DAC0D;AAC1D,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;IACtE,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAC,CA0BD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { uploadArtifact } from './upload.js';
|
|
7
|
+
import { basename } from 'node:path';
|
|
8
|
+
/** Resolve `react-native/scripts/compose-source-maps.js` from the
|
|
9
|
+
* current project's node_modules. Returns null if react-native isn't
|
|
10
|
+
* installed or the version doesn't ship that script. */
|
|
11
|
+
export function resolveComposeScript(fromDir = process.cwd()) {
|
|
12
|
+
const req = createRequire(join(fromDir, 'noop.js'));
|
|
13
|
+
for (const id of [
|
|
14
|
+
'react-native/scripts/compose-source-maps.js',
|
|
15
|
+
'@react-native/community-cli-plugin/dist/utils/composeSourceMaps.js',
|
|
16
|
+
]) {
|
|
17
|
+
try {
|
|
18
|
+
const p = req.resolve(id);
|
|
19
|
+
if (existsSync(p))
|
|
20
|
+
return p;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// try next
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/** Compose a Metro packager source map + a Hermes source map into a
|
|
29
|
+
* single map (a temp file the caller is responsible for deleting).
|
|
30
|
+
* Throws if react-native's compose script can't be found or fails. */
|
|
31
|
+
export function composeSourceMaps(metroMap, hermesMap) {
|
|
32
|
+
for (const p of [metroMap, hermesMap]) {
|
|
33
|
+
if (!existsSync(p))
|
|
34
|
+
throw new Error(`no such file: ${p}`);
|
|
35
|
+
}
|
|
36
|
+
const script = resolveComposeScript();
|
|
37
|
+
if (!script) {
|
|
38
|
+
throw new Error("couldn't find react-native's compose-source-maps.js — install react-native, or " +
|
|
39
|
+
'compose the maps yourself and use `sentori-cli upload sourcemap <composed.map>`');
|
|
40
|
+
}
|
|
41
|
+
const out = join(mkdtempSync(join(tmpdir(), 'sentori-rn-')), 'composed.map');
|
|
42
|
+
const r = spawnSync('node', [script, metroMap, hermesMap, '-o', out], { stdio: 'inherit' });
|
|
43
|
+
if (r.status !== 0) {
|
|
44
|
+
throw new Error(`compose-source-maps.js exited with ${r.status ?? 'signal'}`);
|
|
45
|
+
}
|
|
46
|
+
if (!existsSync(out))
|
|
47
|
+
throw new Error('compose-source-maps.js produced no output');
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/** Compose the Metro + Hermes maps, then upload the result (and the
|
|
51
|
+
* bundle, if given). Cleans up the temp composed map. */
|
|
52
|
+
export async function reactNativeUpload(opts) {
|
|
53
|
+
const composed = composeSourceMaps(opts.metroMap, opts.hermesMap);
|
|
54
|
+
try {
|
|
55
|
+
const paths = [composed, ...(opts.bundle ? [opts.bundle] : [])];
|
|
56
|
+
if (opts.dryRun)
|
|
57
|
+
return { files: paths };
|
|
58
|
+
let uploaded = 0;
|
|
59
|
+
for (const p of paths) {
|
|
60
|
+
await uploadArtifact({
|
|
61
|
+
apiUrl: opts.apiUrl,
|
|
62
|
+
token: opts.token,
|
|
63
|
+
release: opts.release,
|
|
64
|
+
kind: 'sourcemap',
|
|
65
|
+
path: p,
|
|
66
|
+
name: basename(p),
|
|
67
|
+
});
|
|
68
|
+
uploaded += 1;
|
|
69
|
+
}
|
|
70
|
+
return { files: paths, uploaded };
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
try {
|
|
74
|
+
rmSync(composed, { force: true });
|
|
75
|
+
rmSync(join(composed, '..'), { force: true, recursive: true });
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// best-effort cleanup
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=react-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native.js","sourceRoot":"","sources":["../src/react-native.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AdminUpload } from './native-artifacts.js';
|
|
2
|
+
export type SourceBundleUploadOptions = AdminUpload & {
|
|
3
|
+
/** v1.4 W26 — optional module label so polyrepo apps (main +
|
|
4
|
+
* watch ext + share ext etc.) can upload multiple bundles per
|
|
5
|
+
* (release, platform). Empty/undefined → unlabelled single
|
|
6
|
+
* bundle (v1.3 W15 behaviour). */
|
|
7
|
+
module?: string;
|
|
8
|
+
/** Pre-built tar.gz archive of the project's source tree. */
|
|
9
|
+
path: string;
|
|
10
|
+
platform: 'android' | 'ios';
|
|
11
|
+
};
|
|
12
|
+
export type SourceBundleUploadResult = {
|
|
13
|
+
contentHash: string;
|
|
14
|
+
kind: string;
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function uploadSourceBundle(opts: SourceBundleUploadOptions): Promise<SourceBundleUploadResult>;
|
|
18
|
+
/** Walk `dir`, pick platform-relevant source files, and tar.gz them
|
|
19
|
+
* into a temp file. Caller is responsible for invoking `cleanup()`.
|
|
20
|
+
* Uses the system `tar` binary; that's portable enough on macOS +
|
|
21
|
+
* Linux + WSL, which covers every realistic CI environment Sentori
|
|
22
|
+
* ships to. Native Windows CI without WSL would need to gzip the
|
|
23
|
+
* archive themselves (the pre-built-path mode still works). */
|
|
24
|
+
export declare function buildSourceBundleFromDir(dir: string, platform: 'android' | 'ios'): Promise<{
|
|
25
|
+
cleanup: () => Promise<void>;
|
|
26
|
+
path: string;
|
|
27
|
+
}>;
|
|
28
|
+
//# sourceMappingURL=source-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-bundle.d.ts","sourceRoot":"","sources":["../src/source-bundle.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAyBxD,MAAM,MAAM,yBAAyB,GAAG,WAAW,GAAG;IACpD;;;uCAGmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CA6BnC;AAuDD;;;;;gEAKgE;AAChE,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,GAAG,KAAK,GAC1B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCzD"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// v1.2 W3.a — `sentori-cli upload source-bundle`.
|
|
2
|
+
//
|
|
3
|
+
// Uploads a pre-built `*.tar.gz` archive of the project's source tree
|
|
4
|
+
// for one platform. Server stores it under
|
|
5
|
+
// `release_artifacts` with `kind = source_bundle_<platform>`; on
|
|
6
|
+
// click-frame, the dashboard's FrameSourceDrawer pulls the matching
|
|
7
|
+
// source file out of the archive and shows ±N lines.
|
|
8
|
+
//
|
|
9
|
+
// We intentionally keep the CLI side small: the operator (or CI)
|
|
10
|
+
// already knows how to build a tarball. v1.3 may add an
|
|
11
|
+
// auto-bundle-from-directory mode; for now you do:
|
|
12
|
+
//
|
|
13
|
+
// tar -czf ios-source.tar.gz Sources/
|
|
14
|
+
// sentori-cli upload source-bundle --project <uuid> \
|
|
15
|
+
// --release myapp@1.0.0 --platform ios --path ios-source.tar.gz
|
|
16
|
+
import { spawnSync } from 'node:child_process';
|
|
17
|
+
import { mkdtemp, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { tmpdir } from 'node:os';
|
|
19
|
+
import { join, relative, sep as pathSep } from 'node:path';
|
|
20
|
+
const PLATFORMS = new Set(['ios', 'android']);
|
|
21
|
+
/** v1.2 W3.d — per-platform file extensions the CLI bundles when
|
|
22
|
+
* `--from-dir` mode picks files from a project tree. Kept narrow on
|
|
23
|
+
* purpose: source-bundle is only useful for native source viewing,
|
|
24
|
+
* and including non-source files would balloon the archive without
|
|
25
|
+
* helping the lookup path. */
|
|
26
|
+
const EXTENSIONS = {
|
|
27
|
+
android: ['.kt', '.java'],
|
|
28
|
+
ios: ['.swift', '.m', '.mm', '.h', '.hpp'],
|
|
29
|
+
};
|
|
30
|
+
const SKIP_DIRS = new Set([
|
|
31
|
+
'.git',
|
|
32
|
+
'node_modules',
|
|
33
|
+
'Pods',
|
|
34
|
+
'build',
|
|
35
|
+
'DerivedData',
|
|
36
|
+
'.gradle',
|
|
37
|
+
'.build',
|
|
38
|
+
'target',
|
|
39
|
+
]);
|
|
40
|
+
export async function uploadSourceBundle(opts) {
|
|
41
|
+
if (!PLATFORMS.has(opts.platform)) {
|
|
42
|
+
throw new Error(`--platform must be 'ios' or 'android' (got '${opts.platform}')`);
|
|
43
|
+
}
|
|
44
|
+
if (!opts.release) {
|
|
45
|
+
throw new Error('--release is required for source-bundle uploads');
|
|
46
|
+
}
|
|
47
|
+
// v1.2 W3.d: when `opts.path` is a directory, bundle it on the fly
|
|
48
|
+
// instead of requiring the operator to pre-build the archive.
|
|
49
|
+
let archivePath = opts.path;
|
|
50
|
+
let cleanup;
|
|
51
|
+
try {
|
|
52
|
+
const st = await stat(opts.path);
|
|
53
|
+
if (st.isDirectory()) {
|
|
54
|
+
const built = await buildSourceBundleFromDir(opts.path, opts.platform);
|
|
55
|
+
archivePath = built.path;
|
|
56
|
+
cleanup = built.cleanup;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
if (e.code !== 'ENOENT')
|
|
61
|
+
throw e;
|
|
62
|
+
throw new Error(`source path not found: ${opts.path}`);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return await uploadPrebuiltTarGz({ ...opts, path: archivePath });
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
if (cleanup)
|
|
69
|
+
await cleanup();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function uploadPrebuiltTarGz(opts) {
|
|
73
|
+
const body = await readFile(opts.path);
|
|
74
|
+
if (body.length === 0)
|
|
75
|
+
throw new Error(`empty archive: ${opts.path}`);
|
|
76
|
+
// Same gzip magic check the server enforces. Failing early here
|
|
77
|
+
// saves a network round-trip when an operator accidentally points
|
|
78
|
+
// at a raw .tar.
|
|
79
|
+
if (body.length < 2 || body[0] !== 0x1f || body[1] !== 0x8b) {
|
|
80
|
+
throw new Error(`${opts.path} does not look like a gzip stream (expected 1f 8b magic) — ` +
|
|
81
|
+
`did you mean to gzip it first? \`tar -czf <out>.tar.gz <dir>/\``);
|
|
82
|
+
}
|
|
83
|
+
if (!opts.release)
|
|
84
|
+
throw new Error('--release is required for source-bundle uploads');
|
|
85
|
+
const base = opts.apiUrl.replace(/\/+$/, '');
|
|
86
|
+
const q = new URLSearchParams();
|
|
87
|
+
q.set('release', opts.release);
|
|
88
|
+
q.set('platform', opts.platform);
|
|
89
|
+
if (opts.module)
|
|
90
|
+
q.set('module', opts.module);
|
|
91
|
+
const url = `${base}/admin/api/projects/${encodeURIComponent(opts.projectId)}/source-bundles?${q.toString()}`;
|
|
92
|
+
const resp = await fetch(url, {
|
|
93
|
+
body,
|
|
94
|
+
headers: {
|
|
95
|
+
Authorization: `Bearer ${opts.token}`,
|
|
96
|
+
'Content-Type': 'application/gzip',
|
|
97
|
+
},
|
|
98
|
+
method: 'POST',
|
|
99
|
+
});
|
|
100
|
+
if (!resp.ok) {
|
|
101
|
+
let detail = '';
|
|
102
|
+
try {
|
|
103
|
+
detail = await resp.text();
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// ignore
|
|
107
|
+
}
|
|
108
|
+
throw new Error(`${resp.status} ${resp.statusText}${detail ? ` — ${detail.slice(0, 300)}` : ''}`);
|
|
109
|
+
}
|
|
110
|
+
const parsed = await resp.json();
|
|
111
|
+
if (!parsed ||
|
|
112
|
+
typeof parsed !== 'object' ||
|
|
113
|
+
typeof parsed.contentHash !== 'string') {
|
|
114
|
+
throw new Error(`unexpected response shape: ${JSON.stringify(parsed)}`);
|
|
115
|
+
}
|
|
116
|
+
const r = parsed;
|
|
117
|
+
return { contentHash: r.contentHash, kind: r.kind, sizeBytes: r.sizeBytes };
|
|
118
|
+
}
|
|
119
|
+
/** Walk `dir`, pick platform-relevant source files, and tar.gz them
|
|
120
|
+
* into a temp file. Caller is responsible for invoking `cleanup()`.
|
|
121
|
+
* Uses the system `tar` binary; that's portable enough on macOS +
|
|
122
|
+
* Linux + WSL, which covers every realistic CI environment Sentori
|
|
123
|
+
* ships to. Native Windows CI without WSL would need to gzip the
|
|
124
|
+
* archive themselves (the pre-built-path mode still works). */
|
|
125
|
+
export async function buildSourceBundleFromDir(dir, platform) {
|
|
126
|
+
const exts = EXTENSIONS[platform];
|
|
127
|
+
const files = [];
|
|
128
|
+
await walk(dir, dir, exts, files);
|
|
129
|
+
if (files.length === 0) {
|
|
130
|
+
throw new Error(`no ${platform} source files (${exts.join(', ')}) found under ${dir} — ` +
|
|
131
|
+
`pass --platform with the right value or check your source layout`);
|
|
132
|
+
}
|
|
133
|
+
files.sort();
|
|
134
|
+
// Write the file list to a temp file, then have tar consume it via
|
|
135
|
+
// -T —. Avoids the per-arg shell length cap on huge projects.
|
|
136
|
+
const tmp = await mkdtemp(join(tmpdir(), 'sentori-srcbun-'));
|
|
137
|
+
const listPath = join(tmp, 'files.txt');
|
|
138
|
+
const archivePath = join(tmp, `${platform}-source.tar.gz`);
|
|
139
|
+
await writeFile(listPath, files.join('\n'));
|
|
140
|
+
const r = spawnSync('tar', ['-czf', archivePath, '-C', dir, '-T', listPath]);
|
|
141
|
+
if (r.status !== 0) {
|
|
142
|
+
throw new Error(`tar failed (status ${r.status}): ${(r.stderr ?? '').toString().slice(0, 300)}`);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
cleanup: async () => {
|
|
146
|
+
try {
|
|
147
|
+
await readdir(tmp).then(async (entries) => {
|
|
148
|
+
for (const e of entries) {
|
|
149
|
+
await unlinkIfExists(join(tmp, e));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
await unlinkIfExists(tmp, true);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// best-effort cleanup
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
path: archivePath,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function walk(root, dir, exts, out) {
|
|
162
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
163
|
+
for (const e of entries) {
|
|
164
|
+
if (e.name.startsWith('.') && e.isDirectory() && e.name !== '.') {
|
|
165
|
+
// Hidden directory: skip (.git, .gradle, .build…). The known
|
|
166
|
+
// ones are listed in SKIP_DIRS for clarity, but any leading-dot
|
|
167
|
+
// dir is also skipped as a safety net.
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (SKIP_DIRS.has(e.name))
|
|
171
|
+
continue;
|
|
172
|
+
const full = join(dir, e.name);
|
|
173
|
+
if (e.isDirectory()) {
|
|
174
|
+
await walk(root, full, exts, out);
|
|
175
|
+
}
|
|
176
|
+
else if (e.isFile()) {
|
|
177
|
+
const lower = e.name.toLowerCase();
|
|
178
|
+
if (exts.some((ext) => lower.endsWith(ext))) {
|
|
179
|
+
out.push(relative(root, full).split(pathSep).join('/'));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function unlinkIfExists(path, isDir = false) {
|
|
185
|
+
const { rm } = await import('node:fs/promises');
|
|
186
|
+
try {
|
|
187
|
+
await rm(path, { force: true, recursive: isDir });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// ignore
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=source-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-bundle.js","sourceRoot":"","sources":["../src/source-bundle.ts"],"names":[],"mappings":"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"}
|
package/lib/upload.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type UploadOpts = {
|
|
2
|
+
apiUrl: string;
|
|
3
|
+
token: string;
|
|
4
|
+
release: string;
|
|
5
|
+
kind: 'dsym' | 'proguard' | 'sourcemap';
|
|
6
|
+
path: string;
|
|
7
|
+
/** Override the stored artifact name (defaults to the filename). */
|
|
8
|
+
name?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function uploadArtifact(opts: UploadOpts): Promise<{
|
|
11
|
+
id: string;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB9E"}
|
package/lib/upload.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Unified symbolication-artifact upload: sourcemap / dsym / proguard
|
|
2
|
+
// all land on `POST /v1/releases/{release}/artifacts` (multipart
|
|
3
|
+
// `kind` + `file`), authenticated with an api-scope token. A late
|
|
4
|
+
// upload triggers retro-symbolication server-side, which is what
|
|
5
|
+
// makes the lenient exit-0 contract honest — nothing is lost
|
|
6
|
+
// forever.
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { basename } from 'node:path';
|
|
9
|
+
export async function uploadArtifact(opts) {
|
|
10
|
+
const bytes = readFileSync(opts.path);
|
|
11
|
+
if (bytes.length === 0)
|
|
12
|
+
throw new Error(`empty file: ${opts.path}`);
|
|
13
|
+
const form = new FormData();
|
|
14
|
+
form.append('kind', opts.kind);
|
|
15
|
+
form.append('file', new Blob([new Uint8Array(bytes)]), opts.name ?? basename(opts.path));
|
|
16
|
+
const url = `${opts.apiUrl.replace(/\/+$/, '')}/v1/releases/${encodeURIComponent(opts.release)}/artifacts`;
|
|
17
|
+
const resp = await fetch(url, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { Authorization: `Bearer ${opts.token}` },
|
|
20
|
+
body: form,
|
|
21
|
+
});
|
|
22
|
+
if (!resp.ok) {
|
|
23
|
+
const detail = await resp.text().catch(() => '');
|
|
24
|
+
throw new Error(`${resp.status} ${resp.statusText}${detail ? ` — ${detail.slice(0, 200)}` : ''}`);
|
|
25
|
+
}
|
|
26
|
+
return (await resp.json());
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,iEAAiE;AACjE,kEAAkE;AAClE,iEAAiE;AACjE,6DAA6D;AAC7D,WAAW;AAEX,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAYpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAgB;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAEnE,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,MAAM,CACT,MAAM,EACN,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EACjC,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CACjC,CAAA;IAED,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAA;IAC1G,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC5B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE;QAClD,IAAI,EAAE,IAAI;KACX,CAAC,CAAA;IACF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;QAChD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAmB,CAAA;AAC9C,CAAC"}
|