@fnndsc/stratus 0.0.0-stage → 0.1.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -2
  3. package/dist/args.d.ts +26 -0
  4. package/dist/args.js +43 -0
  5. package/dist/args.js.map +1 -0
  6. package/dist/backend.d.ts +40 -0
  7. package/dist/backend.js +38 -0
  8. package/dist/backend.js.map +1 -0
  9. package/dist/cache.d.ts +33 -0
  10. package/dist/cache.js +50 -0
  11. package/dist/cache.js.map +1 -0
  12. package/dist/cloud/driver.d.ts +140 -0
  13. package/dist/cloud/driver.js +18 -0
  14. package/dist/cloud/driver.js.map +1 -0
  15. package/dist/cloud/fake/driver.d.ts +55 -0
  16. package/dist/cloud/fake/driver.js +115 -0
  17. package/dist/cloud/fake/driver.js.map +1 -0
  18. package/dist/cloud/oci/api.d.ts +81 -0
  19. package/dist/cloud/oci/api.js +184 -0
  20. package/dist/cloud/oci/api.js.map +1 -0
  21. package/dist/cloud/oci/driver.d.ts +42 -0
  22. package/dist/cloud/oci/driver.js +131 -0
  23. package/dist/cloud/oci/driver.js.map +1 -0
  24. package/dist/cloud/oci/prices.d.ts +73 -0
  25. package/dist/cloud/oci/prices.js +105 -0
  26. package/dist/cloud/oci/prices.js.map +1 -0
  27. package/dist/index.d.ts +19 -0
  28. package/dist/index.js +20 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/names.d.ts +51 -0
  31. package/dist/names.js +53 -0
  32. package/dist/names.js.map +1 -0
  33. package/dist/session.d.ts +48 -0
  34. package/dist/session.js +128 -0
  35. package/dist/session.js.map +1 -0
  36. package/dist/stratus.d.ts +2 -0
  37. package/dist/stratus.js +90 -0
  38. package/dist/stratus.js.map +1 -0
  39. package/dist/vfs/look.d.ts +9 -0
  40. package/dist/vfs/look.js +60 -0
  41. package/dist/vfs/look.js.map +1 -0
  42. package/dist/vfs/tenancy.d.ts +94 -0
  43. package/dist/vfs/tenancy.js +393 -0
  44. package/dist/vfs/tenancy.js.map +1 -0
  45. package/package.json +63 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prices.js","sourceRoot":"","sources":["../../../src/cloud/oci/prices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file `@fnndsc/stratus`: a mise session over the cloud substrate a Trusted
3
+ * Domain runs on. One backend, clouds as drivers, OCI first
4
+ * (docs/stratus.adoc).
5
+ *
6
+ * @module
7
+ */
8
+ export * from './cloud/driver.js';
9
+ export { FakeDriver, fakeCloud_sample, availabilityKey_make, type FakeCloud } from './cloud/fake/driver.js';
10
+ export { OciDriver, ociTags_flatten, shape_ofRecord, type OciDriverOptions } from './cloud/oci/driver.js';
11
+ export { ociApi_make, type OciApi, type OciApiOptions, type OciCompartmentRecord, type OciLimitValueRecord, type OciShapeRecord, type OciTenancyRecord } from './cloud/oci/api.js';
12
+ export { SHAPE_TERMS, familyName_derive, shapeTerms_get, partPrices_index, shapePrices_map, ociPrices_read, PRICE_LIST_URL, type ShapeTerms, type JsonFetch } from './cloud/oci/prices.js';
13
+ export { TenancyProvider, TENANCY_RESERVED, CONTAINER_RESERVED, READ_ONLY_REASON, type TenancyProviderOptions } from './vfs/tenancy.js';
14
+ export { stratusListingLook, stratusName_colorize, STRATUS_ITEM_KINDS, CONTAINER_TYPES } from './vfs/look.js';
15
+ export { StratusSession, configDir_default, type StratusSessionOptions } from './session.js';
16
+ export { stratusBackend_make, type StratusBackend, type StratusBackendOptions } from './backend.js';
17
+ export { AnswerCache } from './cache.js';
18
+ export { segments_assign, segment_resolve, idSuffix_of, ambiguity_words, type Named, type Segment, type SegmentMatch } from './names.js';
19
+ export { stratusArgs_parse, type StratusArgs } from './args.js';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @file `@fnndsc/stratus`: a mise session over the cloud substrate a Trusted
3
+ * Domain runs on. One backend, clouds as drivers, OCI first
4
+ * (docs/stratus.adoc).
5
+ *
6
+ * @module
7
+ */
8
+ export * from './cloud/driver.js';
9
+ export { FakeDriver, fakeCloud_sample, availabilityKey_make } from './cloud/fake/driver.js';
10
+ export { OciDriver, ociTags_flatten, shape_ofRecord } from './cloud/oci/driver.js';
11
+ export { ociApi_make } from './cloud/oci/api.js';
12
+ export { SHAPE_TERMS, familyName_derive, shapeTerms_get, partPrices_index, shapePrices_map, ociPrices_read, PRICE_LIST_URL } from './cloud/oci/prices.js';
13
+ export { TenancyProvider, TENANCY_RESERVED, CONTAINER_RESERVED, READ_ONLY_REASON } from './vfs/tenancy.js';
14
+ export { stratusListingLook, stratusName_colorize, STRATUS_ITEM_KINDS, CONTAINER_TYPES } from './vfs/look.js';
15
+ export { StratusSession, configDir_default } from './session.js';
16
+ export { stratusBackend_make } from './backend.js';
17
+ export { AnswerCache } from './cache.js';
18
+ export { segments_assign, segment_resolve, idSuffix_of, ambiguity_words } from './names.js';
19
+ export { stratusArgs_parse } from './args.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAkB,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAyB,MAAM,uBAAuB,CAAC;AAC1G,OAAO,EAAE,WAAW,EAAoI,MAAM,oBAAoB,CAAC;AACnL,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAmC,MAAM,uBAAuB,CAAC;AAC3L,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAA+B,MAAM,kBAAkB,CAAC;AACxI,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC9G,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAA8B,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAmD,MAAM,cAAc,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAA+C,MAAM,YAAY,CAAC;AACzI,OAAO,EAAE,iBAAiB,EAAoB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @file Names in paths: display names, never ids, and what happens when two
3
+ * share one (docs/stratus.adoc, D4).
4
+ *
5
+ * A duplicate shows as `name~<last six of its id>`; the plain name refuses
6
+ * as ambiguous, never picks one. The rule holds wherever a path is resolved.
7
+ *
8
+ * @module
9
+ */
10
+ /** Something with a display name and an id. */
11
+ export interface Named {
12
+ readonly name: string;
13
+ readonly id: string;
14
+ }
15
+ /** A path segment and the thing it names. */
16
+ export interface Segment<T extends Named> {
17
+ readonly segment: string;
18
+ readonly item: T;
19
+ }
20
+ /** The suffix a duplicate wears: the last six characters of its id. */
21
+ export declare function idSuffix_of(id: string): string;
22
+ /**
23
+ * The path segment for each item: its name, or `name~<id6>` when another
24
+ * item in the same listing has the same name.
25
+ *
26
+ * @param items - The listing.
27
+ * @returns A segment per item, in the same order.
28
+ */
29
+ export declare function segments_assign<T extends Named>(items: ReadonlyArray<T>): Segment<T>[];
30
+ /** What resolving a segment came to. */
31
+ export type SegmentMatch<T extends Named> = {
32
+ readonly kind: 'one';
33
+ readonly item: T;
34
+ } | {
35
+ readonly kind: 'none';
36
+ } | {
37
+ readonly kind: 'ambiguous';
38
+ readonly segments: string[];
39
+ };
40
+ /**
41
+ * The item a path segment names: the plain name when one item has it, the
42
+ * suffixed form when several do, and a refusal naming every suffixed form
43
+ * when the plain name is asked for a duplicate.
44
+ *
45
+ * @param items - The listing the segment is resolved in.
46
+ * @param segment - The segment as typed.
47
+ * @returns The match.
48
+ */
49
+ export declare function segment_resolve<T extends Named>(items: ReadonlyArray<T>, segment: string): SegmentMatch<T>;
50
+ /** The words a refusal of an ambiguous name uses. */
51
+ export declare function ambiguity_words(segment: string, segments: ReadonlyArray<string>): string;
package/dist/names.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @file Names in paths: display names, never ids, and what happens when two
3
+ * share one (docs/stratus.adoc, D4).
4
+ *
5
+ * A duplicate shows as `name~<last six of its id>`; the plain name refuses
6
+ * as ambiguous, never picks one. The rule holds wherever a path is resolved.
7
+ *
8
+ * @module
9
+ */
10
+ /** The suffix a duplicate wears: the last six characters of its id. */
11
+ export function idSuffix_of(id) {
12
+ return id.slice(-6);
13
+ }
14
+ /**
15
+ * The path segment for each item: its name, or `name~<id6>` when another
16
+ * item in the same listing has the same name.
17
+ *
18
+ * @param items - The listing.
19
+ * @returns A segment per item, in the same order.
20
+ */
21
+ export function segments_assign(items) {
22
+ const counts = new Map();
23
+ for (const item of items)
24
+ counts.set(item.name, (counts.get(item.name) ?? 0) + 1);
25
+ return items.map((item) => ({
26
+ segment: (counts.get(item.name) ?? 0) > 1 ? `${item.name}~${idSuffix_of(item.id)}` : item.name,
27
+ item,
28
+ }));
29
+ }
30
+ /**
31
+ * The item a path segment names: the plain name when one item has it, the
32
+ * suffixed form when several do, and a refusal naming every suffixed form
33
+ * when the plain name is asked for a duplicate.
34
+ *
35
+ * @param items - The listing the segment is resolved in.
36
+ * @param segment - The segment as typed.
37
+ * @returns The match.
38
+ */
39
+ export function segment_resolve(items, segment) {
40
+ const assigned = segments_assign(items);
41
+ const exact = assigned.find((entry) => entry.segment === segment);
42
+ if (exact !== undefined)
43
+ return { kind: 'one', item: exact.item };
44
+ const sameName = assigned.filter((entry) => entry.item.name === segment);
45
+ if (sameName.length === 0)
46
+ return { kind: 'none' };
47
+ return { kind: 'ambiguous', segments: sameName.map((entry) => entry.segment) };
48
+ }
49
+ /** The words a refusal of an ambiguous name uses. */
50
+ export function ambiguity_words(segment, segments) {
51
+ return `${segment}: ambiguous: ${segments.join(', ')}`;
52
+ }
53
+ //# sourceMappingURL=names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../src/names.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAkB,KAAuB;IACtE,MAAM,MAAM,GAAwB,IAAI,GAAG,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAO,EAAc,EAAE,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QAC9F,IAAI;KACL,CAAC,CAAC,CAAC;AACN,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAkB,KAAuB,EAAE,OAAe;IACvF,MAAM,QAAQ,GAAiB,eAAe,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,KAAK,GAA2B,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAiB,EAAW,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IAC/G,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAiB,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAiB,EAAW,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAC5G,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAiB,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;AACrG,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,QAA+B;IAC9E,OAAO,GAAG,OAAO,gBAAgB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { BackendSession, SessionIdentity } from '@fnndsc/brasa/core';
2
+ import type { CloudDriver, CloudIdentity } from './cloud/driver.js';
3
+ /** Where mise keeps a user's configuration. */
4
+ export declare function configDir_default(env?: NodeJS.ProcessEnv): string;
5
+ /** How a session is made. */
6
+ export interface StratusSessionOptions {
7
+ readonly driver: CloudDriver;
8
+ /** The region the session works in; the credential's home region when absent. */
9
+ readonly region?: string;
10
+ /** Where the working directory is kept; the user's configuration directory when absent. */
11
+ readonly configDir?: string;
12
+ }
13
+ /** The session over a cloud. */
14
+ export declare class StratusSession implements BackendSession {
15
+ private readonly driver;
16
+ private readonly configDir;
17
+ private readonly regionAsked;
18
+ private cloudIdentity;
19
+ private failure;
20
+ private cwd;
21
+ private regionCurrent;
22
+ constructor(options: StratusSessionOptions);
23
+ /** The cloud's short name. */
24
+ get cloud(): string;
25
+ /** Why the session is not connected, or null when it is. */
26
+ get disconnectedReason(): string | null;
27
+ /** The cloud identity, or null when not connected. */
28
+ get identity(): CloudIdentity | null;
29
+ /** The session's region, or null when not connected and none was asked. */
30
+ get region(): string | null;
31
+ /** Changes the session's region. */
32
+ region_set(region: string): void;
33
+ /** The mount the tenancy lives under. */
34
+ get mount(): string;
35
+ /** The tenancy's folder, or the mount when not connected. */
36
+ get tenancyPath(): string;
37
+ init(): Promise<void>;
38
+ identity_get(): Promise<SessionIdentity>;
39
+ user_get(): Promise<string | null>;
40
+ home_get(): Promise<string>;
41
+ cwd_load(): Promise<string | null>;
42
+ cwd_save(cwd: string): Promise<void>;
43
+ /** The working directory as it stands, for the prompt. */
44
+ cwd_get(): string | null;
45
+ /** The file the working directory is kept in, or null when not connected. */
46
+ private cwdFile_get;
47
+ private cwd_read;
48
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @file The stratus session: who it is, where it starts, where it left off.
3
+ *
4
+ * The identity is the cloud user at the tenancy (`rudolph@fnndsc`), the
5
+ * berth a daemon advertises; disconnected, it is `disconnected@<cloud>`, so
6
+ * two disconnected substrate daemons never share a name with each other or
7
+ * with a ChRIS one. Home is the tenancy's `domains/`. The working directory
8
+ * is kept per identity under the user's configuration directory, so a
9
+ * restarted daemon stands where it stood. The region is the session's
10
+ * (docs/stratus.adoc, D4 and D8).
11
+ *
12
+ * @module
13
+ */
14
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { homedir } from 'node:os';
16
+ import path from 'node:path';
17
+ /** Where mise keeps a user's configuration. */
18
+ export function configDir_default(env = process.env) {
19
+ return path.join(env['XDG_CONFIG_HOME'] ?? path.join(homedir(), '.config'), 'mise', 'stratus');
20
+ }
21
+ /** The session over a cloud. */
22
+ export class StratusSession {
23
+ driver;
24
+ configDir;
25
+ regionAsked;
26
+ cloudIdentity = null;
27
+ failure = null;
28
+ cwd = null;
29
+ regionCurrent = null;
30
+ constructor(options) {
31
+ this.driver = options.driver;
32
+ this.configDir = options.configDir ?? configDir_default();
33
+ this.regionAsked = options.region;
34
+ }
35
+ /** The cloud's short name. */
36
+ get cloud() {
37
+ return this.driver.cloud;
38
+ }
39
+ /** Why the session is not connected, or null when it is. */
40
+ get disconnectedReason() {
41
+ return this.failure;
42
+ }
43
+ /** The cloud identity, or null when not connected. */
44
+ get identity() {
45
+ return this.cloudIdentity;
46
+ }
47
+ /** The session's region, or null when not connected and none was asked. */
48
+ get region() {
49
+ return this.regionCurrent ?? this.regionAsked ?? null;
50
+ }
51
+ /** Changes the session's region. */
52
+ region_set(region) {
53
+ this.regionCurrent = region;
54
+ }
55
+ /** The mount the tenancy lives under. */
56
+ get mount() {
57
+ return `/net/${this.driver.cloud}`;
58
+ }
59
+ /** The tenancy's folder, or the mount when not connected. */
60
+ get tenancyPath() {
61
+ return this.cloudIdentity === null ? this.mount : `${this.mount}/${this.cloudIdentity.tenancy}`;
62
+ }
63
+ async init() {
64
+ try {
65
+ this.cloudIdentity = await this.driver.identity_get();
66
+ this.failure = null;
67
+ if (this.regionCurrent === null)
68
+ this.regionCurrent = this.regionAsked ?? this.cloudIdentity.homeRegion;
69
+ }
70
+ catch (error) {
71
+ this.cloudIdentity = null;
72
+ this.failure = error instanceof Error ? error.message : String(error);
73
+ }
74
+ this.cwd = this.cwd_read();
75
+ }
76
+ async identity_get() {
77
+ if (this.cloudIdentity === null)
78
+ return { user: 'disconnected', where: this.driver.cloud, connected: false };
79
+ return { user: this.cloudIdentity.user, where: this.cloudIdentity.tenancy, connected: true };
80
+ }
81
+ async user_get() {
82
+ return this.cloudIdentity?.user ?? null;
83
+ }
84
+ async home_get() {
85
+ return this.cloudIdentity === null ? this.mount : `${this.tenancyPath}/domains`;
86
+ }
87
+ async cwd_load() {
88
+ return this.cwd;
89
+ }
90
+ async cwd_save(cwd) {
91
+ this.cwd = cwd;
92
+ const file = this.cwdFile_get();
93
+ if (file === null)
94
+ return;
95
+ try {
96
+ mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
97
+ writeFileSync(file, `${cwd}\n`, { mode: 0o600 });
98
+ }
99
+ catch {
100
+ // Deliberate absorption: a working directory that cannot be kept is
101
+ // still the working directory; the next start begins at home.
102
+ }
103
+ }
104
+ /** The working directory as it stands, for the prompt. */
105
+ cwd_get() {
106
+ return this.cwd;
107
+ }
108
+ /** The file the working directory is kept in, or null when not connected. */
109
+ cwdFile_get() {
110
+ if (this.cloudIdentity === null)
111
+ return null;
112
+ const berth = `${this.cloudIdentity.user}@${this.cloudIdentity.tenancy}`.replace(/[^A-Za-z0-9@._-]/g, '_');
113
+ return path.join(this.configDir, berth, 'cwd');
114
+ }
115
+ cwd_read() {
116
+ const file = this.cwdFile_get();
117
+ if (file === null)
118
+ return null;
119
+ try {
120
+ const text = readFileSync(file, 'utf-8').trim();
121
+ return text === '' ? null : text;
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ }
128
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file The `stratus` command: hosts a substrate session as a calypso daemon.
4
+ *
5
+ * stratus ships its own launcher (docs/stratus.adoc, D2): it composes the
6
+ * engine with the stratus backend over the OCI driver and hands it to
7
+ * calypso's `daemon_launch`; calypso itself knows nothing of stratus. The
8
+ * daemon runs on the bastion, the host that holds the cloud credential.
9
+ *
10
+ * Usage:
11
+ * stratus [--profile NAME] [--config FILE] [--region REGION]
12
+ * [--host-control[=TIERS]] [--expose-host-control]
13
+ * stratus --fake a session over the fake cloud, for tests
14
+ *
15
+ * @module
16
+ */
17
+ import { realpathSync } from 'node:fs';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { engine_create } from '@fnndsc/brasa/core';
20
+ import { daemon_launch, daemonConsole_run, hostControl_parseArgv, packageWebRoot_find } from '@fnndsc/calypso';
21
+ import { stratusBackend_make } from './backend.js';
22
+ import { FakeDriver, fakeCloud_sample } from './cloud/fake/driver.js';
23
+ import { OciDriver } from './cloud/oci/driver.js';
24
+ import { ociApi_make } from './cloud/oci/api.js';
25
+ import { stratusArgs_parse } from './args.js';
26
+ const USAGE = [
27
+ 'stratus: a mise session over the cloud substrate a Trusted Domain runs on.',
28
+ '',
29
+ 'Usage: stratus [--profile NAME] [--config FILE] [--region REGION]',
30
+ ' [--host-control[=shell,files,pipes]] [--expose-host-control]',
31
+ ' stratus --fake',
32
+ '',
33
+ ' --profile NAME the ~/.oci/config profile (DEFAULT)',
34
+ ' --config FILE the OCI configuration file (~/.oci/config)',
35
+ ' --region REGION the region the session works in (the profile\'s)',
36
+ ' --fake host a session over the fake cloud, for tests',
37
+ ].join('\n');
38
+ /**
39
+ * Hosts the daemon.
40
+ */
41
+ async function stratus_start() {
42
+ const parsed = stratusArgs_parse(process.argv.slice(2));
43
+ if ('error' in parsed) {
44
+ console.error(`[!] ${parsed.error}`);
45
+ process.exit(1);
46
+ }
47
+ if (parsed.args.help) {
48
+ console.log(USAGE);
49
+ return;
50
+ }
51
+ const driver = parsed.args.fake
52
+ ? new FakeDriver(fakeCloud_sample())
53
+ : new OciDriver({ api: ociApi_make({ configFile: parsed.args.configFile, profile: parsed.args.profile }) });
54
+ const made = stratusBackend_make({ driver, region: parsed.args.region });
55
+ const engine = await engine_create(made.backend);
56
+ if (made.session.identity === null) {
57
+ console.error(`[!] Not connected to ${driver.cloud}: ${made.session.disconnectedReason ?? 'no credential'}; hosting offline.`);
58
+ }
59
+ else {
60
+ console.error(`[+] ${made.session.identity.user}@${made.session.identity.tenancy} on ${driver.cloud}, region ${made.session.region}.`);
61
+ }
62
+ const parsedPolicy = hostControl_parseArgv(process.argv, process.env);
63
+ if ('error' in parsedPolicy) {
64
+ console.error(`[!] ${parsedPolicy.error}`);
65
+ process.exit(1);
66
+ }
67
+ const policy = parsedPolicy.policy;
68
+ const info = await daemon_launch(engine, undefined, {
69
+ hostControl: policy,
70
+ webRoot: packageWebRoot_find('@fnndsc/argus'),
71
+ });
72
+ if (process.stdin.isTTY === true && process.stdout.isTTY === true) {
73
+ await daemonConsole_run({ identity: info.identity, url: info.url, token: info.token });
74
+ }
75
+ }
76
+ const currentFile = fileURLToPath(import.meta.url);
77
+ let isMain = false;
78
+ try {
79
+ isMain = realpathSync(process.argv[1]) === realpathSync(currentFile);
80
+ }
81
+ catch {
82
+ // Not invoked as a script.
83
+ }
84
+ if (isMain) {
85
+ stratus_start().catch((error) => {
86
+ console.error(`[!] stratus: ${error instanceof Error ? error.message : String(error)}`);
87
+ process.exit(1);
88
+ });
89
+ }
90
+ //# sourceMappingURL=stratus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stratus.js","sourceRoot":"","sources":["../src/stratus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type ItemKindLook, type ListingLook } from '@fnndsc/fond';
2
+ /** The container nouns every cloud maps onto (docs/stratus.adoc, D4). */
3
+ export declare const CONTAINER_TYPES: ReadonlyArray<string>;
4
+ /** The kinds stratus lists beside the core's. */
5
+ export declare const STRATUS_ITEM_KINDS: ReadonlyArray<ItemKindLook>;
6
+ /** Colours a name by the item's kind and state. */
7
+ export declare function stratusName_colorize(name: string, type: string, status?: string): string;
8
+ /** The look of a stratus listing. */
9
+ export declare const stratusListingLook: ListingLook;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @file How a stratus listing shows: its item kinds and the colour of a name.
3
+ *
4
+ * Every row is a folder or a file to the shell (docs/stratus.adoc, D5); the
5
+ * kind is how `ls -l` draws it: the container nouns, the resource kinds, the
6
+ * facts under `regions/`. A name is coloured by its kind and, where the item
7
+ * carries one, its lifecycle state: running green, stopped dim, provisioning
8
+ * amber, failed red, as jobs are by status.
9
+ *
10
+ * @module
11
+ */
12
+ import chalk from 'chalk';
13
+ import { LISTING_CORE_KINDS } from '@fnndsc/fond';
14
+ /** The container nouns every cloud maps onto (docs/stratus.adoc, D4). */
15
+ export const CONTAINER_TYPES = ['tenancy', 'compartment', 'account', 'organization', 'project', 'folder', 'subscription', 'resourcegroup', 'managementgroup'];
16
+ /** The kinds stratus lists beside the core's. */
17
+ export const STRATUS_ITEM_KINDS = [
18
+ ...CONTAINER_TYPES.map((type) => ({ type, mark: 'c', container: true, sizeColumn: state_column })),
19
+ { type: 'region', mark: 'r', container: true },
20
+ { type: 'zone', mark: 'z', container: true },
21
+ { type: 'service', mark: 'd', container: true },
22
+ { type: 'limit', mark: 'L', container: true },
23
+ { type: 'shape', mark: 's', container: true },
24
+ { type: 'price', mark: '$', container: true },
25
+ { type: 'domain', mark: 'D', container: true, sizeColumn: state_column },
26
+ ];
27
+ /** The long view's size column for an item with a state: the state. */
28
+ function state_column(item) {
29
+ return item.status !== undefined && item.status !== '' ? item.status : null;
30
+ }
31
+ /** States and the tone each is drawn in. */
32
+ const STATE_TONES = [
33
+ { matches: /^(running|active|available|attached|ready|done)$/, paint: chalk.green },
34
+ { matches: /^(stopped|inactive|terminated|deleted|detached)$/, paint: chalk.dim },
35
+ { matches: /^(provisioning|creating|starting|stopping|updating|deleting|terminating|moving|queued|pending)$/, paint: chalk.yellow },
36
+ { matches: /^(failed|faulted|error|unknown_value)$/, paint: chalk.red },
37
+ ];
38
+ /** Colours a name by the item's kind and state. */
39
+ export function stratusName_colorize(name, type, status) {
40
+ if (status !== undefined) {
41
+ const tone = STATE_TONES.find((entry) => entry.matches.test(status.toLowerCase()));
42
+ if (tone !== undefined)
43
+ return tone.paint(name);
44
+ }
45
+ if (CONTAINER_TYPES.includes(type) || type === 'dir')
46
+ return chalk.blue(name);
47
+ if (type === 'region' || type === 'zone')
48
+ return chalk.cyan(name);
49
+ if (type === 'domain')
50
+ return chalk.magenta(name);
51
+ if (type === 'shape' || type === 'price' || type === 'limit' || type === 'service')
52
+ return chalk.white(name);
53
+ return name;
54
+ }
55
+ /** The look of a stratus listing. */
56
+ export const stratusListingLook = {
57
+ kinds: [...LISTING_CORE_KINDS, ...STRATUS_ITEM_KINDS],
58
+ name_colorize: (name, type) => stratusName_colorize(name, type),
59
+ };
60
+ //# sourceMappingURL=look.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"look.js","sourceRoot":"","sources":["../../src/vfs/look.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @file The tenancy as a tree: `/net/<cloud>/<tenancy>/…` (docs/stratus.adoc, D4).
3
+ *
4
+ * A fond provider over the cloud driver. Under the mount: the tenancy by its
5
+ * display name; inside it, its containers (compartments) nesting as the cloud
6
+ * nests them, `regions/` with each region's zones, limits, shapes and prices,
7
+ * and `domains/`. A container lists its children and `info.json`; a fact
8
+ * (a limit, a shape, a price) is a folder of field files, as `/proc` does it:
9
+ * a field is a file when a shell line wants it, and `info.json` holds the
10
+ * whole record.
11
+ *
12
+ * Names in paths are display names; a duplicate wears `~<id6>` and the plain
13
+ * name refuses as ambiguous (`names.ts`). Kind folders and `info.json` are
14
+ * reserved, so a container with such a name wears the suffix too. Every
15
+ * answer is kept for a short life (`cache.ts`). The mount is read-only: the
16
+ * substrate changes through `domain` (D6).
17
+ *
18
+ * @module
19
+ */
20
+ import { type CpOptions, type Result, type VFSItem, type VFSProvider, type VfsOutcome } from '@fnndsc/fond';
21
+ import type { CloudDriver } from '../cloud/driver.js';
22
+ import { AnswerCache } from '../cache.js';
23
+ /** The folders a tenancy level reserves beside its containers. */
24
+ export declare const TENANCY_RESERVED: ReadonlyArray<string>;
25
+ /** The folders a container level reserves beside its children. */
26
+ export declare const CONTAINER_RESERVED: ReadonlyArray<string>;
27
+ /** The words a refusal of a write uses. */
28
+ export declare const READ_ONLY_REASON: string;
29
+ /** How the provider is made. */
30
+ export interface TenancyProviderOptions {
31
+ readonly driver: CloudDriver;
32
+ /** The cache; a fresh one with a minute's life when absent. */
33
+ readonly cache?: AnswerCache;
34
+ /** The clock for item dates the cloud does not give. */
35
+ readonly now?: () => string;
36
+ }
37
+ /** The tenancy as a tree under `/net/<cloud>`. */
38
+ export declare class TenancyProvider implements VFSProvider {
39
+ readonly prefix: string;
40
+ private readonly driver;
41
+ private readonly cache;
42
+ private readonly now;
43
+ constructor(options: TenancyProviderOptions);
44
+ /** Forgets every kept answer: the next listing asks the cloud. */
45
+ cache_clear(): void;
46
+ private identity_get;
47
+ private root_get;
48
+ private containers_list;
49
+ private regions_list;
50
+ private zones_list;
51
+ private services_list;
52
+ private limits_list;
53
+ private availability_get;
54
+ private shapes_list;
55
+ private prices_list;
56
+ /** The path's segments under the mount; null when the path is not under it. */
57
+ private segments_of;
58
+ /** Containers with their path segments: a reserved name or a duplicate wears the suffix. */
59
+ private containerSegments_of;
60
+ /** The child a segment names among containers, with the reserved rule. */
61
+ private container_resolve;
62
+ /**
63
+ * The node a path names.
64
+ *
65
+ * @param pathStr - The absolute path.
66
+ * @returns The node, or `missing` with a reason to show.
67
+ */
68
+ private node_resolve;
69
+ /** Walks container segments from a parent. */
70
+ private containerNode_resolve;
71
+ /** Walks `regions/…`. */
72
+ private regionNode_resolve;
73
+ private zoneNode_resolve;
74
+ private limitNode_resolve;
75
+ private shapeNode_resolve;
76
+ private priceNode_resolve;
77
+ /** A field file in a folder of fields, by its remaining segments. */
78
+ private fieldNode_resolve;
79
+ /** A limit's fields: its value and scope, and what is used and left when the cloud says. */
80
+ private limit_fields;
81
+ private folder_item;
82
+ private file_item;
83
+ private container_item;
84
+ /** What a container level lists: its children, the reserved folders, `info.json`. */
85
+ private containerLevel_list;
86
+ /** What a node lists. */
87
+ private node_list;
88
+ list(pathStr: string): Promise<Result<VFSItem[]>>;
89
+ read(pathStr: string): Promise<VfsOutcome<string>>;
90
+ readBinary(pathStr: string): Promise<VfsOutcome<Buffer>>;
91
+ cp(): Promise<VfsOutcome>;
92
+ }
93
+ /** A `cp` the provider refuses, typed for the interface. */
94
+ export type ReadOnlyCp = (src: string, dest: string, options: CpOptions) => Promise<VfsOutcome>;