run402 4.31.0 → 4.32.1
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/cli.mjs +1 -1
- package/core-dist/binding-file.js +83 -0
- package/lib/events.mjs +28 -14
- package/lib/wallet-context.mjs +14 -53
- package/package.json +1 -1
- package/sdk/core-dist/binding-file.js +83 -0
- package/sdk/dist/namespaces/events.d.ts +13 -4
- package/sdk/dist/namespaces/events.d.ts.map +1 -1
- package/sdk/dist/namespaces/events.js +13 -4
- package/sdk/dist/namespaces/events.js.map +1 -1
- package/sdk/dist/namespaces/events.types.d.ts +52 -11
- package/sdk/dist/namespaces/events.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/events.types.js +12 -2
- package/sdk/dist/namespaces/events.types.js.map +1 -1
package/cli.mjs
CHANGED
|
@@ -63,7 +63,7 @@ Commands:
|
|
|
63
63
|
ai AI translation and moderation tools
|
|
64
64
|
image Generate AI images via x402 or MPP micropayments
|
|
65
65
|
email Send template-based emails from your project
|
|
66
|
-
|
|
66
|
+
feedback Send feedback to the Run402 developers (free with an active tier)
|
|
67
67
|
auth Manage project user authentication (magic link, passwords, settings)
|
|
68
68
|
billing Email organizations, Stripe tier checkout, email packs
|
|
69
69
|
contracts KMS signers ($0.04/day rental + $0.000005/sign)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-directory binding file — `.run402.json`, and its gitignored personal
|
|
3
|
+
* override `.run402.local.json`.
|
|
4
|
+
*
|
|
5
|
+
* A checkout binds itself to a wallet profile, an organization, a room, by
|
|
6
|
+
* committing a small JSON file. That is a CHECKOUT-LEVEL CONTRACT, not a CLI
|
|
7
|
+
* implementation detail: every agent working in the directory inherits the
|
|
8
|
+
* same one, whichever surface it reaches Run402 through.
|
|
9
|
+
*
|
|
10
|
+
* It lives in core because two surfaces now read it. The CLI has always walked
|
|
11
|
+
* this chain; the MCP server needs the same answer for the same directory, and
|
|
12
|
+
* `run402-mcp` ships only `dist` + `core/dist` + `sdk/dist` — `cli/` is not in
|
|
13
|
+
* the published package, so the MCP server cannot import the CLI's copy even
|
|
14
|
+
* if it wanted to. One reader, in the one place both can see it, rather than
|
|
15
|
+
* two that agree until they don't.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately pure: `node:fs` + `node:path`, no logging, no process exit, no
|
|
18
|
+
* validation of what a value MEANS. Callers decide whether a value is
|
|
19
|
+
* well-shaped and what to do when it isn't — the CLI exits, the MCP server
|
|
20
|
+
* returns an error, and neither behaviour belongs in a file reader.
|
|
21
|
+
*
|
|
22
|
+
* Unknown keys are ignored on purpose: that is what makes an older client
|
|
23
|
+
* forward-compatible with a binding file written by a newer one.
|
|
24
|
+
*/
|
|
25
|
+
import { readFileSync } from "node:fs";
|
|
26
|
+
import { dirname, join, resolve } from "node:path";
|
|
27
|
+
/** The committed binding file. Safe to check in — it names, never authorizes. */
|
|
28
|
+
export const BINDING_FILE = ".run402.json";
|
|
29
|
+
/** The personal override. Gitignored; beats the committed file key-by-key. */
|
|
30
|
+
export const BINDING_LOCAL_FILE = ".run402.local.json";
|
|
31
|
+
/** Read one key from a single directory's binding files, override first. */
|
|
32
|
+
function readBindingKeyFrom(dir, key) {
|
|
33
|
+
for (const fname of [BINDING_LOCAL_FILE, BINDING_FILE]) {
|
|
34
|
+
const p = join(dir, fname);
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(readFileSync(p, "utf8"));
|
|
37
|
+
const v = parsed?.[key];
|
|
38
|
+
if (typeof v === "string" && v.trim())
|
|
39
|
+
return { value: v.trim(), file: p };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
/* missing / unreadable / malformed → skip */
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Nearest binding of `key`, walking up from `startDir` to the filesystem root.
|
|
49
|
+
*
|
|
50
|
+
* Resolution is PER KEY, not per file: the nearest file that carries the key
|
|
51
|
+
* wins, so `/work/.run402.json` may supply the organization while
|
|
52
|
+
* `/work/api/.run402.json` supplies the wallet. A worktree nested under a bound
|
|
53
|
+
* checkout therefore inherits the binding without restating it.
|
|
54
|
+
*/
|
|
55
|
+
export function findBindingKey(startDir, key) {
|
|
56
|
+
let dir = resolve(startDir);
|
|
57
|
+
for (;;) {
|
|
58
|
+
const hit = readBindingKeyFrom(dir, key);
|
|
59
|
+
if (hit)
|
|
60
|
+
return hit;
|
|
61
|
+
const parent = dirname(dir);
|
|
62
|
+
if (parent === dir)
|
|
63
|
+
return null;
|
|
64
|
+
dir = parent;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Path of the committed binding file for a directory. */
|
|
68
|
+
export function bindingFilePath(dir = process.cwd()) {
|
|
69
|
+
return join(dir, BINDING_FILE);
|
|
70
|
+
}
|
|
71
|
+
/** Parse a directory's committed binding file, or `{}` when absent/unreadable. */
|
|
72
|
+
export function readBindingFile(dir = process.cwd()) {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(readFileSync(bindingFilePath(dir), "utf8"));
|
|
75
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
76
|
+
? parsed
|
|
77
|
+
: {};
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=binding-file.js.map
|
package/lib/events.mjs
CHANGED
|
@@ -30,7 +30,8 @@ Usage:
|
|
|
30
30
|
|
|
31
31
|
Options:
|
|
32
32
|
--project <id> Project to read (defaults to the active project)
|
|
33
|
-
--org <id> Read the org-wide feed instead
|
|
33
|
+
--org <id> Read the org-wide feed instead — a SUPERSET of the project
|
|
34
|
+
feeds: it also carries org-level facts (project_id null)
|
|
34
35
|
--cursor <cursor> Opaque cursor from a previous response. Returns events strictly
|
|
35
36
|
after it. Omit on first contact to start from the earliest
|
|
36
37
|
retained event.
|
|
@@ -52,28 +53,41 @@ App events vs platform events:
|
|
|
52
53
|
one your app already uses — the source field is what disambiguates.
|
|
53
54
|
Omit --source to read both lanes in one merged, cursor-ordered feed.
|
|
54
55
|
|
|
55
|
-
The cursor model:
|
|
56
|
+
The cursor model — an id is not a cursor:
|
|
56
57
|
- Every response carries "cursor": the high-water mark. Store it (a file in
|
|
57
58
|
your repo, a memory note — wherever you keep state) and pass it back as
|
|
58
59
|
--cursor next time. One call then returns everything you missed.
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
cursor
|
|
60
|
+
- Two opaque tokens, and they are different things. An event's "id" names a
|
|
61
|
+
FACT: the same event has the same id in the project feed and the org feed,
|
|
62
|
+
which is how you dedup across both. The page "cursor" names a POSITION,
|
|
63
|
+
and a position only means something inside the row set it came from.
|
|
64
|
+
- So a cursor is NOT portable. Replaying a --project cursor against --org,
|
|
65
|
+
an unfiltered cursor against a --source/--type read, or an event "id" in
|
|
66
|
+
place of a cursor all return "reset": true instead of resuming — because
|
|
67
|
+
resuming would silently skip exactly the rows the other view omitted.
|
|
68
|
+
Store each cursor against the read shape that produced it.
|
|
69
|
+
- Never parse or compare either token.
|
|
70
|
+
- Events become visible within a couple of seconds of the change committing.
|
|
71
|
+
That watermark is a bound, not a proof: it gives a write's commit window
|
|
72
|
+
time to close, so in practice a cursor read misses nothing that committed
|
|
73
|
+
before it was issued.
|
|
65
74
|
- "has_more": true means more events are immediately available — call again
|
|
66
75
|
with the new cursor right away.
|
|
67
76
|
|
|
68
|
-
When your cursor is
|
|
77
|
+
When your cursor is unusable (reset semantics):
|
|
69
78
|
- Feed retention is 90 days (365 for security/recovery/billing-critical
|
|
70
|
-
classes). A cursor older than that —
|
|
71
|
-
with "reset": true and "earliest_cursor":
|
|
72
|
-
Nothing is silently skipped; you are told
|
|
73
|
-
to proceed.
|
|
79
|
+
classes). A cursor older than that — malformed, from another view, or an
|
|
80
|
+
event id — still returns 200, with "reset": true and "earliest_cursor":
|
|
81
|
+
the point to restart from. Nothing is silently skipped; you are told
|
|
82
|
+
exactly what happened and how to proceed.
|
|
74
83
|
|
|
75
84
|
Event shape:
|
|
76
|
-
{ "id", "event_type", "class", "occurred_at", "payload",
|
|
85
|
+
{ "id", "project_id", "event_type", "class", "occurred_at", "payload",
|
|
86
|
+
"next_actions" }
|
|
87
|
+
project_id is what the fact is ABOUT. It is null for an org-level fact —
|
|
88
|
+
one that belongs to the org and to no project, visible only via --org. It
|
|
89
|
+
may also name a project that no longer exists: a fact outlives the project
|
|
90
|
+
it describes, so deleting a project no longer erases its history.
|
|
77
91
|
event_type is flat snake_case: deploy_activated, mailbox_suspended,
|
|
78
92
|
project_transfer_completed, organization_past_due, verification_failed,
|
|
79
93
|
webhook_disabled, ... Each event's next_actions[] is the platform's own
|
package/lib/wallet-context.mjs
CHANGED
|
@@ -19,15 +19,26 @@
|
|
|
19
19
|
* wallets and no flag is given, that is a hard error (not a silent pick).
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { existsSync,
|
|
23
|
-
import { join
|
|
22
|
+
import { existsSync, rmSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
24
|
import { fail } from "./sdk-errors.mjs";
|
|
25
25
|
import { isValidProfileName } from "../core-dist/config.js";
|
|
26
26
|
import { getDefaultWallet, profileExists, readMeta, profileDir } from "../core-dist/profiles.js";
|
|
27
27
|
import { readAllowance } from "../core-dist/allowance.js";
|
|
28
|
+
// The binding file is a CHECKOUT-LEVEL CONTRACT read by more than one surface,
|
|
29
|
+
// so its reader lives in core — `run402-mcp` ships core/dist but not cli/, and
|
|
30
|
+
// two readers of one file format is exactly the drift worth not having.
|
|
31
|
+
// Re-exported here under the names the rest of the CLI already imports.
|
|
32
|
+
import {
|
|
33
|
+
findBindingKey,
|
|
34
|
+
bindingFilePath,
|
|
35
|
+
readBindingFile,
|
|
36
|
+
BINDING_FILE,
|
|
37
|
+
} from "../core-dist/binding-file.js";
|
|
38
|
+
|
|
39
|
+
export { findBindingKey, bindingFilePath, readBindingFile };
|
|
28
40
|
|
|
29
41
|
const DEFAULT = "default";
|
|
30
|
-
const BINDING_FILE = ".run402.json";
|
|
31
42
|
const GLOBAL_FLAGS = new Set(["--wallet", "--profile"]);
|
|
32
43
|
// The `wallets` group is the management + escape surface — it must work even
|
|
33
44
|
// when selection is ambiguous (so you can `wallets unbind`), and it validates
|
|
@@ -70,36 +81,6 @@ export function splitWalletFlag(rawArgv = []) {
|
|
|
70
81
|
return { argv, walletFlag: flag };
|
|
71
82
|
}
|
|
72
83
|
|
|
73
|
-
function readBindingKeyFrom(dir, key) {
|
|
74
|
-
// .run402.local.json (gitignored personal override) beats .run402.json.
|
|
75
|
-
for (const fname of [".run402.local.json", ".run402.json"]) {
|
|
76
|
-
const p = join(dir, fname);
|
|
77
|
-
try {
|
|
78
|
-
const parsed = JSON.parse(readFileSync(p, "utf8"));
|
|
79
|
-
const v = parsed?.[key];
|
|
80
|
-
if (typeof v === "string" && v.trim()) return { value: v.trim(), file: p };
|
|
81
|
-
} catch {
|
|
82
|
-
/* missing / unreadable / malformed → skip */
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Path of the committed binding file for a directory. */
|
|
89
|
-
export function bindingFilePath(dir = process.cwd()) {
|
|
90
|
-
return join(dir, BINDING_FILE);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Parse a directory's committed binding file, or `{}` when absent/unreadable. */
|
|
94
|
-
export function readBindingFile(dir = process.cwd()) {
|
|
95
|
-
try {
|
|
96
|
-
const parsed = JSON.parse(readFileSync(bindingFilePath(dir), "utf8"));
|
|
97
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
98
|
-
} catch {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
84
|
/**
|
|
104
85
|
* MERGE keys into a directory's binding file. A `null` value removes its key;
|
|
105
86
|
* a file left with no keys is deleted rather than committed empty.
|
|
@@ -124,26 +105,6 @@ export function updateBindingFile(dir, patch) {
|
|
|
124
105
|
return { file, contents: next, removed: false };
|
|
125
106
|
}
|
|
126
107
|
|
|
127
|
-
/**
|
|
128
|
-
* Nearest binding carrying `key`, walking up from `startDir` to the root.
|
|
129
|
-
*
|
|
130
|
-
* Keys bind INDEPENDENTLY (add-cli-current-org, design D7): a file declaring
|
|
131
|
-
* only `org` leaves wallet resolution untouched, and each key resolves at the
|
|
132
|
-
* nearest file that carries it — so `/work/.run402.json` may supply the org
|
|
133
|
-
* while `/work/api/.run402.json` supplies the wallet. Unknown keys are ignored,
|
|
134
|
-
* which is what makes older CLIs forward-compatible with these files.
|
|
135
|
-
*/
|
|
136
|
-
export function findBindingKey(startDir, key) {
|
|
137
|
-
let dir = resolve(startDir);
|
|
138
|
-
for (;;) {
|
|
139
|
-
const hit = readBindingKeyFrom(dir, key);
|
|
140
|
-
if (hit) return hit;
|
|
141
|
-
const parent = dirname(dir);
|
|
142
|
-
if (parent === dir) return null;
|
|
143
|
-
dir = parent;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
108
|
/** Nearest wallet binding walking up from `startDir` to the filesystem root. */
|
|
148
109
|
export function findBinding(startDir) {
|
|
149
110
|
const hit = findBindingKey(startDir, "wallet");
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-directory binding file — `.run402.json`, and its gitignored personal
|
|
3
|
+
* override `.run402.local.json`.
|
|
4
|
+
*
|
|
5
|
+
* A checkout binds itself to a wallet profile, an organization, a room, by
|
|
6
|
+
* committing a small JSON file. That is a CHECKOUT-LEVEL CONTRACT, not a CLI
|
|
7
|
+
* implementation detail: every agent working in the directory inherits the
|
|
8
|
+
* same one, whichever surface it reaches Run402 through.
|
|
9
|
+
*
|
|
10
|
+
* It lives in core because two surfaces now read it. The CLI has always walked
|
|
11
|
+
* this chain; the MCP server needs the same answer for the same directory, and
|
|
12
|
+
* `run402-mcp` ships only `dist` + `core/dist` + `sdk/dist` — `cli/` is not in
|
|
13
|
+
* the published package, so the MCP server cannot import the CLI's copy even
|
|
14
|
+
* if it wanted to. One reader, in the one place both can see it, rather than
|
|
15
|
+
* two that agree until they don't.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately pure: `node:fs` + `node:path`, no logging, no process exit, no
|
|
18
|
+
* validation of what a value MEANS. Callers decide whether a value is
|
|
19
|
+
* well-shaped and what to do when it isn't — the CLI exits, the MCP server
|
|
20
|
+
* returns an error, and neither behaviour belongs in a file reader.
|
|
21
|
+
*
|
|
22
|
+
* Unknown keys are ignored on purpose: that is what makes an older client
|
|
23
|
+
* forward-compatible with a binding file written by a newer one.
|
|
24
|
+
*/
|
|
25
|
+
import { readFileSync } from "node:fs";
|
|
26
|
+
import { dirname, join, resolve } from "node:path";
|
|
27
|
+
/** The committed binding file. Safe to check in — it names, never authorizes. */
|
|
28
|
+
export const BINDING_FILE = ".run402.json";
|
|
29
|
+
/** The personal override. Gitignored; beats the committed file key-by-key. */
|
|
30
|
+
export const BINDING_LOCAL_FILE = ".run402.local.json";
|
|
31
|
+
/** Read one key from a single directory's binding files, override first. */
|
|
32
|
+
function readBindingKeyFrom(dir, key) {
|
|
33
|
+
for (const fname of [BINDING_LOCAL_FILE, BINDING_FILE]) {
|
|
34
|
+
const p = join(dir, fname);
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(readFileSync(p, "utf8"));
|
|
37
|
+
const v = parsed?.[key];
|
|
38
|
+
if (typeof v === "string" && v.trim())
|
|
39
|
+
return { value: v.trim(), file: p };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
/* missing / unreadable / malformed → skip */
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Nearest binding of `key`, walking up from `startDir` to the filesystem root.
|
|
49
|
+
*
|
|
50
|
+
* Resolution is PER KEY, not per file: the nearest file that carries the key
|
|
51
|
+
* wins, so `/work/.run402.json` may supply the organization while
|
|
52
|
+
* `/work/api/.run402.json` supplies the wallet. A worktree nested under a bound
|
|
53
|
+
* checkout therefore inherits the binding without restating it.
|
|
54
|
+
*/
|
|
55
|
+
export function findBindingKey(startDir, key) {
|
|
56
|
+
let dir = resolve(startDir);
|
|
57
|
+
for (;;) {
|
|
58
|
+
const hit = readBindingKeyFrom(dir, key);
|
|
59
|
+
if (hit)
|
|
60
|
+
return hit;
|
|
61
|
+
const parent = dirname(dir);
|
|
62
|
+
if (parent === dir)
|
|
63
|
+
return null;
|
|
64
|
+
dir = parent;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Path of the committed binding file for a directory. */
|
|
68
|
+
export function bindingFilePath(dir = process.cwd()) {
|
|
69
|
+
return join(dir, BINDING_FILE);
|
|
70
|
+
}
|
|
71
|
+
/** Parse a directory's committed binding file, or `{}` when absent/unreadable. */
|
|
72
|
+
export function readBindingFile(dir = process.cwd()) {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(readFileSync(bindingFilePath(dir), "utf8"));
|
|
75
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
76
|
+
? parsed
|
|
77
|
+
: {};
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=binding-file.js.map
|
|
@@ -36,10 +36,19 @@ export declare class Events {
|
|
|
36
36
|
*/
|
|
37
37
|
list(projectId: string, opts?: ListEventsOptions): Promise<ProjectEventFeedPage>;
|
|
38
38
|
/**
|
|
39
|
-
* Read the org-wide feed
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* Read the org-wide feed (`GET /orgs/v1/:org_id/events`) — every fact the
|
|
40
|
+
* organization owns. That is a SUPERSET of its project feeds, not a union
|
|
41
|
+
* of them: it also carries organization-level facts, which belong to no
|
|
42
|
+
* project, arrive with `project_id: null`, and are unreachable from any
|
|
43
|
+
* project feed.
|
|
44
|
+
*
|
|
45
|
+
* Principal-only: requires an active org membership; a project service_key
|
|
46
|
+
* is rejected by the gateway. Same `opts.source` / `opts.eventType` filters
|
|
47
|
+
* as {@link list}.
|
|
48
|
+
*
|
|
49
|
+
* Cursors do NOT interchange with {@link list}, even though an event's `id`
|
|
50
|
+
* is the same in both — a cursor names a position inside one projection.
|
|
51
|
+
* Carrying one across returns `reset: true`; see {@link ListEventsOptions.cursor}.
|
|
43
52
|
*/
|
|
44
53
|
listForOrg(orgId: string, opts?: ListEventsOptions): Promise<ProjectEventFeedPage>;
|
|
45
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/namespaces/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAcjF,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;;;;OAOG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAU1F
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/namespaces/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAcjF,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;;;;OAOG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAU1F;;;;;;;;;;;;;;OAcG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAS7F"}
|
|
@@ -56,10 +56,19 @@ export class Events {
|
|
|
56
56
|
return this.client.request(`/projects/v1/${encodeURIComponent(projectId)}/events${feedQuery(opts)}`, { method: "GET", context: "reading project events feed" });
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Read the org-wide feed
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
59
|
+
* Read the org-wide feed (`GET /orgs/v1/:org_id/events`) — every fact the
|
|
60
|
+
* organization owns. That is a SUPERSET of its project feeds, not a union
|
|
61
|
+
* of them: it also carries organization-level facts, which belong to no
|
|
62
|
+
* project, arrive with `project_id: null`, and are unreachable from any
|
|
63
|
+
* project feed.
|
|
64
|
+
*
|
|
65
|
+
* Principal-only: requires an active org membership; a project service_key
|
|
66
|
+
* is rejected by the gateway. Same `opts.source` / `opts.eventType` filters
|
|
67
|
+
* as {@link list}.
|
|
68
|
+
*
|
|
69
|
+
* Cursors do NOT interchange with {@link list}, even though an event's `id`
|
|
70
|
+
* is the same in both — a cursor names a position inside one projection.
|
|
71
|
+
* Carrying one across returns `reset: true`; see {@link ListEventsOptions.cursor}.
|
|
63
72
|
*/
|
|
64
73
|
async listForOrg(orgId, opts = {}) {
|
|
65
74
|
if (!orgId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/namespaces/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,SAAS,SAAS,CAAC,OAA0B,EAAE;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC7B,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,OAAO,MAAM;IACY;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,OAA0B,EAAE;QACxD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,UAAU,CAAC,kCAAkC,EAAE,6BAA6B,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CACxB,gBAAgB,kBAAkB,CAAC,SAAS,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC,EAAE,EACxE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAC1D,CAAC;IACJ,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/namespaces/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,SAAS,SAAS,CAAC,OAA0B,EAAE;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC7B,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,OAAO,MAAM;IACY;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,OAA0B,EAAE;QACxD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,UAAU,CAAC,kCAAkC,EAAE,6BAA6B,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CACxB,gBAAgB,kBAAkB,CAAC,SAAS,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC,EAAE,EACxE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAC1D,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,OAA0B,EAAE;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,UAAU,CAAC,qCAAqC,EAAE,yBAAyB,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CACxB,YAAY,kBAAkB,CAAC,KAAK,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC,EAAE,EAChE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,yBAAyB,EAAE,CACtD,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
* The feed is the platform's durable, ordered record of operationally
|
|
7
7
|
* significant facts (deploy activations, mailbox suspensions, transfers,
|
|
8
8
|
* lifecycle cliffs, verification outcomes, and `platform_incident`
|
|
9
|
-
* fault-attribution events).
|
|
10
|
-
*
|
|
9
|
+
* fault-attribution events).
|
|
10
|
+
*
|
|
11
|
+
* An ORGANIZATION owns each fact and `project_id` says what it is about, so
|
|
12
|
+
* three things follow. The org feed is a SUPERSET of the project feeds: it
|
|
13
|
+
* also carries organization-level facts, which belong to no project and
|
|
14
|
+
* arrive with `project_id: null`. A fact OUTLIVES the project it describes —
|
|
15
|
+
* deleting a project no longer erases its history, so a row may name a
|
|
16
|
+
* project that no longer exists. And an event's `id` is NOT a page cursor:
|
|
17
|
+
* see {@link ProjectEvent.id} and {@link ListEventsOptions.cursor}.
|
|
18
|
+
*
|
|
19
|
+
* Both tokens are OPAQUE (`evc_…`) — store the page's `cursor`, pass it back
|
|
20
|
+
* as `{ cursor }` next time, and never parse either one. The
|
|
11
21
|
* platform owns the event vocabulary, `next_actions` synthesis, and reset
|
|
12
22
|
* behavior; the SDK passes everything through (index signatures keep unknown
|
|
13
23
|
* future fields, including the additive `platform_incidents[]` overlay and
|
|
@@ -32,10 +42,27 @@ export interface ProjectEventNextAction {
|
|
|
32
42
|
why?: string;
|
|
33
43
|
[key: string]: unknown;
|
|
34
44
|
}
|
|
35
|
-
/** One immutable fact from the
|
|
45
|
+
/** One immutable fact from the events feed. */
|
|
36
46
|
export interface ProjectEvent {
|
|
37
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* This event's opaque identity (`evc_…`). The SAME event carries the SAME
|
|
49
|
+
* `id` in the project feed and the organization feed, which is what lets
|
|
50
|
+
* you dedup across both.
|
|
51
|
+
*
|
|
52
|
+
* NOT a page cursor. An id names a FACT; a cursor names a POSITION inside
|
|
53
|
+
* one projection, and only the page's `cursor` is that. Passing an `id` as
|
|
54
|
+
* `{ cursor }` returns `reset: true` rather than resuming.
|
|
55
|
+
*/
|
|
38
56
|
id: string;
|
|
57
|
+
/**
|
|
58
|
+
* What this fact is ABOUT — `null` for an organization-level fact, which
|
|
59
|
+
* belongs to the organization and to no project. Those appear only on the
|
|
60
|
+
* organization feed; a project feed can never show them.
|
|
61
|
+
*
|
|
62
|
+
* May name a project that NO LONGER EXISTS: a fact outlives the project it
|
|
63
|
+
* describes, so do not assume this resolves.
|
|
64
|
+
*/
|
|
65
|
+
project_id: string | null;
|
|
39
66
|
/** Flat snake_case event name, e.g. `deploy_activated`, `mailbox_suspended`. */
|
|
40
67
|
event_type: string;
|
|
41
68
|
/** Event class stamped at write time (drives retention: mandatory classes keep 365 days, others 90). */
|
|
@@ -50,9 +77,18 @@ export interface ProjectEvent {
|
|
|
50
77
|
/** Options for {@link Events.list} / {@link Events.listForOrg}. */
|
|
51
78
|
export interface ListEventsOptions {
|
|
52
79
|
/**
|
|
53
|
-
* Opaque cursor from a prior page
|
|
54
|
-
*
|
|
55
|
-
*
|
|
80
|
+
* Opaque page cursor from a prior page's `cursor` field. Returns events
|
|
81
|
+
* strictly after it. Omit on first contact to start from the earliest
|
|
82
|
+
* retained event.
|
|
83
|
+
*
|
|
84
|
+
* A page cursor is bound to the PROJECTION that issued it — the feed you
|
|
85
|
+
* read plus any `source` / `eventType` filters. It is not portable:
|
|
86
|
+
* replaying a project feed's cursor against the organization feed, an
|
|
87
|
+
* unfiltered cursor against a filtered read, or an event `id` in place of a
|
|
88
|
+
* cursor all return `reset: true` instead of resuming, because resuming
|
|
89
|
+
* would silently skip exactly the rows the other projection omitted.
|
|
90
|
+
*
|
|
91
|
+
* So key any cursor you persist by the read shape it came from.
|
|
56
92
|
*/
|
|
57
93
|
cursor?: string;
|
|
58
94
|
/** Page size (server default 50, max 200). */
|
|
@@ -81,12 +117,17 @@ export interface ProjectEventFeedPage {
|
|
|
81
117
|
/** True when more events are immediately available past `cursor`. */
|
|
82
118
|
has_more: boolean;
|
|
83
119
|
/**
|
|
84
|
-
* True when the supplied cursor was unusable
|
|
85
|
-
* retention floor
|
|
86
|
-
*
|
|
120
|
+
* True when the supplied cursor was unusable — malformed, older than the
|
|
121
|
+
* retention floor, issued for a DIFFERENT projection (another feed or
|
|
122
|
+
* filter set), or actually an event `id`. The page restarts from the
|
|
123
|
+
* earliest retained event and `earliest_cursor` is provided — never a bare
|
|
124
|
+
* error, never a silent skip.
|
|
87
125
|
*/
|
|
88
126
|
reset: boolean;
|
|
89
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Present only when `reset` is true: a page cursor just before the earliest
|
|
129
|
+
* retained event, issued for the projection you actually read.
|
|
130
|
+
*/
|
|
90
131
|
earliest_cursor?: string;
|
|
91
132
|
/**
|
|
92
133
|
* Sidecar overlay of open GLOBAL (unattributed) platform incidents, each
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/events.types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"events.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/events.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,yHAAyH;IACzH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,4EAA4E;IAC5E,YAAY,EAAE,sBAAsB,EAAE,CAAC;IACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
|
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
* The feed is the platform's durable, ordered record of operationally
|
|
7
7
|
* significant facts (deploy activations, mailbox suspensions, transfers,
|
|
8
8
|
* lifecycle cliffs, verification outcomes, and `platform_incident`
|
|
9
|
-
* fault-attribution events).
|
|
10
|
-
*
|
|
9
|
+
* fault-attribution events).
|
|
10
|
+
*
|
|
11
|
+
* An ORGANIZATION owns each fact and `project_id` says what it is about, so
|
|
12
|
+
* three things follow. The org feed is a SUPERSET of the project feeds: it
|
|
13
|
+
* also carries organization-level facts, which belong to no project and
|
|
14
|
+
* arrive with `project_id: null`. A fact OUTLIVES the project it describes —
|
|
15
|
+
* deleting a project no longer erases its history, so a row may name a
|
|
16
|
+
* project that no longer exists. And an event's `id` is NOT a page cursor:
|
|
17
|
+
* see {@link ProjectEvent.id} and {@link ListEventsOptions.cursor}.
|
|
18
|
+
*
|
|
19
|
+
* Both tokens are OPAQUE (`evc_…`) — store the page's `cursor`, pass it back
|
|
20
|
+
* as `{ cursor }` next time, and never parse either one. The
|
|
11
21
|
* platform owns the event vocabulary, `next_actions` synthesis, and reset
|
|
12
22
|
* behavior; the SDK passes everything through (index signatures keep unknown
|
|
13
23
|
* future fields, including the additive `platform_incidents[]` overlay and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.types.js","sourceRoot":"","sources":["../../src/namespaces/events.types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"events.types.js","sourceRoot":"","sources":["../../src/namespaces/events.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG"}
|