@noodleseed/one 0.38.0 → 0.38.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/billing-ops.d.ts +3 -0
- package/dist/commands/billing-ops.d.ts.map +1 -0
- package/dist/commands/billing-ops.js +144 -0
- package/dist/commands/billing-ops.js.map +1 -0
- package/dist/commands/catalog-data-resources.d.ts.map +1 -1
- package/dist/commands/catalog-data-resources.js +13 -0
- package/dist/commands/catalog-data-resources.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js +5 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.d.ts +6 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.js +23 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts +32 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js +185 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/migration.d.ts +84 -0
- package/node_modules/@noodle-borg/service/dist/billing/migration.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/migration.js +301 -0
- package/node_modules/@noodle-borg/service/dist/billing/migration.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/model.d.ts +85 -0
- package/node_modules/@noodle-borg/service/dist/billing/model.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/model.js +134 -0
- package/node_modules/@noodle-borg/service/dist/billing/model.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts +66 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js +163 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts +4 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js +148 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres.d.ts +26 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres.js +273 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/store.d.ts +27 -0
- package/node_modules/@noodle-borg/service/dist/billing/store.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/store.js +2 -0
- package/node_modules/@noodle-borg/service/dist/billing/store.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/index.d.ts +3 -0
- package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/index.js +2 -0
- package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/options.d.ts +4 -1
- package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/billing.d.ts +14 -0
- package/node_modules/@noodle-borg/service/dist/routes/billing.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/billing.js +76 -0
- package/node_modules/@noodle-borg/service/dist/routes/billing.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts +25 -0
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js +58 -0
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +17 -0
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.js +8 -0
- package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.js +16 -26
- package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js +81 -48
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.js +18 -6
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js +2 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts +14 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js +28 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.js +7 -3
- package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts +4 -0
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.js +13 -0
- package/node_modules/@noodle-borg/service/dist/store/validate.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.d.ts +5 -2
- package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { validateSlug } from '../store/validate.js';
|
|
2
|
+
import { billingIdentityKey, billingMemberKey, createDefaultFreeBillingRecords, FREE_PLAN_VERSION, GOOGLE_CONTROL_PLANE_ISSUER, normalizeBillingEmail, normalizeBillingIdentity, validateBillingAccountId, validateBillingLinkReason, } from './model.js';
|
|
3
|
+
export class InMemoryBillingAccountStore {
|
|
4
|
+
#accounts = new Map();
|
|
5
|
+
#defaults = new Map();
|
|
6
|
+
#members = new Map();
|
|
7
|
+
#snapshots = new Map();
|
|
8
|
+
#activeSnapshots = new Map();
|
|
9
|
+
#orgLinks = new Map();
|
|
10
|
+
#now;
|
|
11
|
+
#orgExists;
|
|
12
|
+
#isOrgOwner;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.#now = options.now ?? (() => new Date());
|
|
15
|
+
this.#orgExists = options.orgExists;
|
|
16
|
+
this.#isOrgOwner = options.isOrgOwner;
|
|
17
|
+
}
|
|
18
|
+
/** Commit the in-memory default-account + initial org-link tuple without an async visibility gap. */
|
|
19
|
+
ensureDefaultAccountAndOrgLinkAtomic(input, createdAt) {
|
|
20
|
+
const identity = normalizeBillingIdentity({
|
|
21
|
+
identityIssuer: input.owner.identityIssuer ?? GOOGLE_CONTROL_PLANE_ISSUER,
|
|
22
|
+
subject: input.owner.subject,
|
|
23
|
+
});
|
|
24
|
+
const accounts = new Map(this.#accounts);
|
|
25
|
+
const defaults = new Map(this.#defaults);
|
|
26
|
+
const members = new Map(this.#members);
|
|
27
|
+
const snapshots = new Map(this.#snapshots);
|
|
28
|
+
const activeSnapshots = new Map(this.#activeSnapshots);
|
|
29
|
+
const orgLinks = new Map(this.#orgLinks);
|
|
30
|
+
try {
|
|
31
|
+
const account = this.#ensureDefaultBillingAccount({ ...identity, email: input.owner.email }, () => createdAt);
|
|
32
|
+
this.#ensureOrgBillingLink({
|
|
33
|
+
org: input.org,
|
|
34
|
+
billingAccountId: account.id,
|
|
35
|
+
homeFreeBillingAccountId: account.id,
|
|
36
|
+
homeOwner: identity,
|
|
37
|
+
linkedBy: identity,
|
|
38
|
+
reason: input.reason,
|
|
39
|
+
}, () => createdAt, true);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
restoreMap(this.#accounts, accounts);
|
|
43
|
+
restoreMap(this.#defaults, defaults);
|
|
44
|
+
restoreMap(this.#members, members);
|
|
45
|
+
restoreMap(this.#snapshots, snapshots);
|
|
46
|
+
restoreMap(this.#activeSnapshots, activeSnapshots);
|
|
47
|
+
restoreMap(this.#orgLinks, orgLinks);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async ensureDefaultBillingAccount(input) {
|
|
52
|
+
return this.#ensureDefaultBillingAccount(input, () => this.#now().toISOString());
|
|
53
|
+
}
|
|
54
|
+
#ensureDefaultBillingAccount(input, createdAt) {
|
|
55
|
+
const identity = normalizeBillingIdentity(input);
|
|
56
|
+
const identityKey = billingIdentityKey(identity);
|
|
57
|
+
const existingId = this.#defaults.get(identityKey);
|
|
58
|
+
if (existingId !== undefined) {
|
|
59
|
+
const account = this.#accounts.get(existingId);
|
|
60
|
+
const snapshotId = this.#activeSnapshots.get(existingId);
|
|
61
|
+
const memberKey = billingMemberKey({ billingAccountId: existingId, ...identity });
|
|
62
|
+
const member = this.#members.get(memberKey);
|
|
63
|
+
if (account === undefined ||
|
|
64
|
+
snapshotId === undefined ||
|
|
65
|
+
!this.#snapshots.has(snapshotId) ||
|
|
66
|
+
member?.role !== 'owner') {
|
|
67
|
+
throw new Error('default billing account is incomplete');
|
|
68
|
+
}
|
|
69
|
+
this.#members.set(memberKey, { ...member, email: normalizeBillingEmail(input.email) });
|
|
70
|
+
return account;
|
|
71
|
+
}
|
|
72
|
+
const created = createDefaultFreeBillingRecords({
|
|
73
|
+
identity,
|
|
74
|
+
email: input.email,
|
|
75
|
+
...(input.displayName !== undefined ? { displayName: input.displayName } : {}),
|
|
76
|
+
createdAt: createdAt(),
|
|
77
|
+
});
|
|
78
|
+
this.#accounts.set(created.account.id, created.account);
|
|
79
|
+
this.#defaults.set(identityKey, created.account.id);
|
|
80
|
+
this.#members.set(billingMemberKey({ billingAccountId: created.account.id, ...identity }), created.member);
|
|
81
|
+
this.#snapshots.set(created.snapshot.id, created.snapshot);
|
|
82
|
+
this.#activeSnapshots.set(created.account.id, created.snapshot.id);
|
|
83
|
+
return created.account;
|
|
84
|
+
}
|
|
85
|
+
getBillingAccount(id) {
|
|
86
|
+
return Promise.resolve(this.#accounts.get(validateBillingAccountId(id)));
|
|
87
|
+
}
|
|
88
|
+
getDefaultBillingAccount(identity) {
|
|
89
|
+
const id = this.#defaults.get(billingIdentityKey(normalizeBillingIdentity(identity)));
|
|
90
|
+
return Promise.resolve(id === undefined ? undefined : this.#accounts.get(id));
|
|
91
|
+
}
|
|
92
|
+
listBillingAccountMembers(id) {
|
|
93
|
+
const billingAccountId = validateBillingAccountId(id);
|
|
94
|
+
return Promise.resolve([...this.#members.values()]
|
|
95
|
+
.filter((member) => member.billingAccountId === billingAccountId)
|
|
96
|
+
.sort((a, b) => a.createdAt.localeCompare(b.createdAt) ||
|
|
97
|
+
a.identityIssuer.localeCompare(b.identityIssuer) ||
|
|
98
|
+
a.subject.localeCompare(b.subject)));
|
|
99
|
+
}
|
|
100
|
+
async removeBillingAccountMember(input) {
|
|
101
|
+
const billingAccountId = validateBillingAccountId(input.billingAccountId);
|
|
102
|
+
const identity = normalizeBillingIdentity(input);
|
|
103
|
+
const key = billingMemberKey({ billingAccountId, ...identity });
|
|
104
|
+
const existing = this.#members.get(key);
|
|
105
|
+
if (existing === undefined)
|
|
106
|
+
return false;
|
|
107
|
+
if (existing.role === 'owner') {
|
|
108
|
+
// Keep the owner-count check and delete in the same synchronous turn. Awaiting the public list
|
|
109
|
+
// method here lets two removals observe the same pre-delete owner set.
|
|
110
|
+
const ownerCount = [...this.#members.values()].filter((member) => member.billingAccountId === billingAccountId && member.role === 'owner').length;
|
|
111
|
+
if (ownerCount <= 1)
|
|
112
|
+
throw new Error('cannot remove the last billing owner');
|
|
113
|
+
}
|
|
114
|
+
if (this.#defaults.get(billingIdentityKey(identity)) === billingAccountId) {
|
|
115
|
+
throw new Error('cannot remove the default billing owner without an atomic default transfer');
|
|
116
|
+
}
|
|
117
|
+
return this.#members.delete(key);
|
|
118
|
+
}
|
|
119
|
+
getPlanVersion(id) {
|
|
120
|
+
return Promise.resolve(id === FREE_PLAN_VERSION.id ? FREE_PLAN_VERSION : undefined);
|
|
121
|
+
}
|
|
122
|
+
getActiveEntitlementSnapshot(billingAccountId) {
|
|
123
|
+
const id = validateBillingAccountId(billingAccountId);
|
|
124
|
+
const snapshotId = this.#activeSnapshots.get(id);
|
|
125
|
+
return Promise.resolve(snapshotId === undefined ? undefined : this.#snapshots.get(snapshotId));
|
|
126
|
+
}
|
|
127
|
+
async ensureOrgBillingLink(input) {
|
|
128
|
+
return this.#ensureOrgBillingLink(input, () => this.#now().toISOString());
|
|
129
|
+
}
|
|
130
|
+
#ensureOrgBillingLink(input, linkedAt, pendingOrg = false) {
|
|
131
|
+
const org = validateSlug('org', input.org);
|
|
132
|
+
if (!pendingOrg && !this.#orgExists(org)) {
|
|
133
|
+
throw new Error('organization not found');
|
|
134
|
+
}
|
|
135
|
+
const reason = validateBillingLinkReason(input.reason);
|
|
136
|
+
const accountId = validateBillingAccountId(input.billingAccountId);
|
|
137
|
+
const homeFreeAccountId = validateBillingAccountId(input.homeFreeBillingAccountId);
|
|
138
|
+
if (accountId !== homeFreeAccountId) {
|
|
139
|
+
throw new Error('initial billing-account link must use the organization home Free account');
|
|
140
|
+
}
|
|
141
|
+
if (!this.#accounts.has(accountId))
|
|
142
|
+
throw new Error('billing account not found');
|
|
143
|
+
const homeOwner = normalizeBillingIdentity(input.homeOwner);
|
|
144
|
+
const ownerDefaultId = this.#defaults.get(billingIdentityKey(homeOwner));
|
|
145
|
+
const ownerMember = this.#members.get(billingMemberKey({ billingAccountId: homeFreeAccountId, ...homeOwner }));
|
|
146
|
+
if (ownerDefaultId !== homeFreeAccountId || ownerMember?.role !== 'owner') {
|
|
147
|
+
throw new Error('organization home Free account must be the home owner default account');
|
|
148
|
+
}
|
|
149
|
+
if (!pendingOrg && !this.#isOrgOwner(org, homeOwner.subject)) {
|
|
150
|
+
throw new Error('organization home Free owner must be a current organization owner');
|
|
151
|
+
}
|
|
152
|
+
const linkedBy = normalizeBillingIdentity(input.linkedBy);
|
|
153
|
+
const existing = this.#orgLinks.get(org);
|
|
154
|
+
if (existing !== undefined) {
|
|
155
|
+
if (existing.billingAccountId !== accountId ||
|
|
156
|
+
existing.homeFreeBillingAccountId !== homeFreeAccountId) {
|
|
157
|
+
throw new Error('organization already has an active billing-account link');
|
|
158
|
+
}
|
|
159
|
+
return existing;
|
|
160
|
+
}
|
|
161
|
+
const record = {
|
|
162
|
+
orgSlug: org,
|
|
163
|
+
billingAccountId: accountId,
|
|
164
|
+
homeFreeBillingAccountId: homeFreeAccountId,
|
|
165
|
+
homeOwner,
|
|
166
|
+
fallbackBillingAccountId: homeFreeAccountId,
|
|
167
|
+
version: 1,
|
|
168
|
+
active: true,
|
|
169
|
+
linkedAt: linkedAt(),
|
|
170
|
+
linkedBy,
|
|
171
|
+
reason,
|
|
172
|
+
};
|
|
173
|
+
this.#orgLinks.set(org, record);
|
|
174
|
+
return record;
|
|
175
|
+
}
|
|
176
|
+
getOrgBillingLink(org) {
|
|
177
|
+
return Promise.resolve(this.#orgLinks.get(validateSlug('org', org)));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function restoreMap(target, source) {
|
|
181
|
+
target.clear();
|
|
182
|
+
for (const [key, value] of source)
|
|
183
|
+
target.set(key, value);
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=in-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory.js","sourceRoot":"","sources":["../../src/billing/in-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ControlPlaneStore } from '../store.js';
|
|
2
|
+
import { type BillingIdentityRef, GOOGLE_CONTROL_PLANE_ISSUER } from './model.js';
|
|
3
|
+
export interface LegacyProductionAppIdentity {
|
|
4
|
+
readonly app: string;
|
|
5
|
+
readonly createdAt: string;
|
|
6
|
+
}
|
|
7
|
+
export interface LegacyUnlinkedOrganizationMapping {
|
|
8
|
+
readonly org: string;
|
|
9
|
+
readonly linkState: 'unlinked';
|
|
10
|
+
readonly defaultBillingOwnerSubject: string;
|
|
11
|
+
readonly productionApps: readonly LegacyProductionAppIdentity[];
|
|
12
|
+
}
|
|
13
|
+
export interface LegacyLinkedOrganizationMapping {
|
|
14
|
+
readonly org: string;
|
|
15
|
+
readonly linkState: 'linked';
|
|
16
|
+
readonly expectedBillingAccountId: string;
|
|
17
|
+
readonly expectedLinkVersion: number;
|
|
18
|
+
readonly productionApps: readonly LegacyProductionAppIdentity[];
|
|
19
|
+
}
|
|
20
|
+
export type LegacyBillingMigrationMapping = LegacyUnlinkedOrganizationMapping | LegacyLinkedOrganizationMapping;
|
|
21
|
+
export interface LegacyBillingMigrationRequest {
|
|
22
|
+
readonly schemaVersion: 1;
|
|
23
|
+
readonly mappings?: readonly LegacyBillingMigrationMapping[];
|
|
24
|
+
}
|
|
25
|
+
export type LegacyBillingMigrationBlockerCode = 'duplicate_org_mapping' | 'duplicate_production_app' | 'existing_link_conflict' | 'linked_organization_not_linked' | 'owner_mapping_required' | 'owner_billing_identity_invalid' | 'owner_not_org_owner' | 'owner_subject_unknown' | 'organization_not_found' | 'production_app_not_active' | 'production_app_not_found' | 'production_classification_required';
|
|
26
|
+
export interface LegacyBillingMigrationBlocker {
|
|
27
|
+
readonly code: LegacyBillingMigrationBlockerCode;
|
|
28
|
+
readonly org: string;
|
|
29
|
+
readonly message: string;
|
|
30
|
+
}
|
|
31
|
+
export interface LegacyBillingMigrationInventory {
|
|
32
|
+
getAppIdentity(org: string, app: string): Promise<{
|
|
33
|
+
readonly createdAt: string;
|
|
34
|
+
readonly active: boolean;
|
|
35
|
+
readonly archivedAt?: string;
|
|
36
|
+
} | undefined>;
|
|
37
|
+
}
|
|
38
|
+
export declare function parseLegacyBillingMigrationRequest(value: unknown): LegacyBillingMigrationRequest;
|
|
39
|
+
export interface LegacyBillingMigrationPreview {
|
|
40
|
+
readonly schemaVersion: 1;
|
|
41
|
+
readonly ready: boolean;
|
|
42
|
+
readonly organizations: readonly {
|
|
43
|
+
readonly org: string;
|
|
44
|
+
readonly ownerCandidates: readonly {
|
|
45
|
+
readonly subject: string;
|
|
46
|
+
readonly email: string;
|
|
47
|
+
}[];
|
|
48
|
+
readonly mappedOwnerSubject?: string;
|
|
49
|
+
readonly productionApps?: readonly LegacyProductionAppIdentity[];
|
|
50
|
+
}[];
|
|
51
|
+
readonly linkedOrganizations: readonly {
|
|
52
|
+
readonly org: string;
|
|
53
|
+
readonly billingAccountId: string;
|
|
54
|
+
readonly homeFreeBillingAccountId: string;
|
|
55
|
+
readonly homeOwner: BillingIdentityRef;
|
|
56
|
+
readonly fallbackBillingAccountId: string;
|
|
57
|
+
readonly version: number;
|
|
58
|
+
readonly productionApps?: readonly LegacyProductionAppIdentity[];
|
|
59
|
+
}[];
|
|
60
|
+
readonly fundingSets: readonly {
|
|
61
|
+
readonly destination: {
|
|
62
|
+
readonly kind: 'existing';
|
|
63
|
+
readonly billingAccountId: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly kind: 'proposed_default';
|
|
66
|
+
readonly identityIssuer: typeof GOOGLE_CONTROL_PLANE_ISSUER;
|
|
67
|
+
readonly subject: string;
|
|
68
|
+
};
|
|
69
|
+
readonly organizations: readonly string[];
|
|
70
|
+
readonly productionApps: readonly (LegacyProductionAppIdentity & {
|
|
71
|
+
readonly org: string;
|
|
72
|
+
})[];
|
|
73
|
+
readonly missingProductionClassifications: readonly string[];
|
|
74
|
+
}[];
|
|
75
|
+
readonly blockers: readonly LegacyBillingMigrationBlocker[];
|
|
76
|
+
readonly grantPolicy: {
|
|
77
|
+
readonly durationDays: 90;
|
|
78
|
+
readonly startsAt: 'billing_enforcement_cutover';
|
|
79
|
+
readonly expiresAt: null;
|
|
80
|
+
readonly eligibility: 'account_cohort_above_capacity';
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export declare function previewLegacyBillingMigration(store: ControlPlaneStore, request: LegacyBillingMigrationRequest, inventory?: LegacyBillingMigrationInventory): Promise<LegacyBillingMigrationPreview>;
|
|
84
|
+
//# sourceMappingURL=migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/billing/migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { isSystemOwnedOrgSlug, validateSlug } from '../store/validate.js';
|
|
3
|
+
import { GOOGLE_CONTROL_PLANE_ISSUER, normalizeBillingEmail, normalizeBillingIdentity, validateBillingAccountId, } from './model.js';
|
|
4
|
+
const appSlugSchema = z
|
|
5
|
+
.string()
|
|
6
|
+
.trim()
|
|
7
|
+
.refine((value) => isValidSlug('app', value), 'invalid app slug');
|
|
8
|
+
const orgSlugSchema = z
|
|
9
|
+
.string()
|
|
10
|
+
.trim()
|
|
11
|
+
.refine((value) => isValidSlug('org', value), 'invalid organization slug');
|
|
12
|
+
const billingAccountIdSchema = z
|
|
13
|
+
.string()
|
|
14
|
+
.trim()
|
|
15
|
+
.refine(isValidBillingAccountId, 'invalid billing account ID');
|
|
16
|
+
const productionAppIdentitySchema = z.strictObject({
|
|
17
|
+
app: appSlugSchema,
|
|
18
|
+
createdAt: z.iso.datetime({ offset: true }).transform((value) => new Date(value).toISOString()),
|
|
19
|
+
});
|
|
20
|
+
const legacyBillingMigrationRequestSchema = z.strictObject({
|
|
21
|
+
schemaVersion: z.literal(1),
|
|
22
|
+
mappings: z
|
|
23
|
+
.array(z.discriminatedUnion('linkState', [
|
|
24
|
+
z.strictObject({
|
|
25
|
+
org: orgSlugSchema,
|
|
26
|
+
linkState: z.literal('unlinked'),
|
|
27
|
+
defaultBillingOwnerSubject: z.string().trim().min(1).max(512),
|
|
28
|
+
productionApps: z.array(productionAppIdentitySchema),
|
|
29
|
+
}),
|
|
30
|
+
z.strictObject({
|
|
31
|
+
org: orgSlugSchema,
|
|
32
|
+
linkState: z.literal('linked'),
|
|
33
|
+
expectedBillingAccountId: billingAccountIdSchema,
|
|
34
|
+
expectedLinkVersion: z.number().int().positive(),
|
|
35
|
+
productionApps: z.array(productionAppIdentitySchema),
|
|
36
|
+
}),
|
|
37
|
+
]))
|
|
38
|
+
.optional(),
|
|
39
|
+
});
|
|
40
|
+
export function parseLegacyBillingMigrationRequest(value) {
|
|
41
|
+
const result = legacyBillingMigrationRequestSchema.safeParse(value);
|
|
42
|
+
if (!result.success) {
|
|
43
|
+
throw new Error(`invalid billing migration preview: ${z.prettifyError(result.error)}`);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
schemaVersion: result.data.schemaVersion,
|
|
47
|
+
...(result.data.mappings !== undefined
|
|
48
|
+
? {
|
|
49
|
+
mappings: result.data.mappings.map((mapping) => ({
|
|
50
|
+
...mapping,
|
|
51
|
+
})),
|
|
52
|
+
}
|
|
53
|
+
: {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export async function previewLegacyBillingMigration(store, request, inventory) {
|
|
57
|
+
if (request.schemaVersion !== 1)
|
|
58
|
+
throw new Error('unsupported billing migration schemaVersion');
|
|
59
|
+
const mappings = request.mappings ?? [];
|
|
60
|
+
const mappingByOrg = new Map();
|
|
61
|
+
const blockers = [];
|
|
62
|
+
for (const mapping of mappings) {
|
|
63
|
+
if (mappingByOrg.has(mapping.org)) {
|
|
64
|
+
blockers.push({
|
|
65
|
+
code: 'duplicate_org_mapping',
|
|
66
|
+
org: mapping.org,
|
|
67
|
+
message: 'organization appears more than once in the mapping document',
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
mappingByOrg.set(mapping.org, mapping);
|
|
72
|
+
}
|
|
73
|
+
const organizations = [];
|
|
74
|
+
const linkedOrganizations = [];
|
|
75
|
+
const fundingSets = new Map();
|
|
76
|
+
const knownOrgs = new Set();
|
|
77
|
+
for (const org of await store.listOrgs()) {
|
|
78
|
+
if (isSystemOwnedOrgSlug(org.slug))
|
|
79
|
+
continue;
|
|
80
|
+
knownOrgs.add(org.slug);
|
|
81
|
+
const existingLink = await store.getOrgBillingLink(org.slug);
|
|
82
|
+
const mapping = mappingByOrg.get(org.slug);
|
|
83
|
+
if (existingLink !== undefined) {
|
|
84
|
+
linkedOrganizations.push({
|
|
85
|
+
org: org.slug,
|
|
86
|
+
billingAccountId: existingLink.billingAccountId,
|
|
87
|
+
homeFreeBillingAccountId: existingLink.homeFreeBillingAccountId,
|
|
88
|
+
homeOwner: existingLink.homeOwner,
|
|
89
|
+
fallbackBillingAccountId: existingLink.fallbackBillingAccountId,
|
|
90
|
+
version: existingLink.version,
|
|
91
|
+
...(mapping?.linkState === 'linked' ? { productionApps: mapping.productionApps } : {}),
|
|
92
|
+
});
|
|
93
|
+
if (mapping === undefined) {
|
|
94
|
+
blockers.push({
|
|
95
|
+
code: 'production_classification_required',
|
|
96
|
+
org: org.slug,
|
|
97
|
+
message: 'already-linked organizations require an asserted link and explicit production-app classification',
|
|
98
|
+
});
|
|
99
|
+
addMissingFundingSet(fundingSets, { kind: 'existing', billingAccountId: existingLink.billingAccountId }, org.slug);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (mapping.linkState !== 'linked' ||
|
|
103
|
+
mapping.expectedBillingAccountId !== existingLink.billingAccountId ||
|
|
104
|
+
mapping.expectedLinkVersion !== existingLink.version) {
|
|
105
|
+
blockers.push({
|
|
106
|
+
code: 'existing_link_conflict',
|
|
107
|
+
org: org.slug,
|
|
108
|
+
message: 'mapping does not match the organization active billing-account link and version',
|
|
109
|
+
});
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const validProductionApps = await validateProductionApps(org.slug, mapping.productionApps, inventory, blockers);
|
|
113
|
+
if (validProductionApps) {
|
|
114
|
+
addToFundingSet(fundingSets, { kind: 'existing', billingAccountId: existingLink.billingAccountId }, org.slug, mapping.productionApps);
|
|
115
|
+
}
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const owners = (await store.listOrgMembers(org.slug))
|
|
119
|
+
.filter((member) => member.role === 'owner')
|
|
120
|
+
.map(({ subject, email }) => ({ subject, email }))
|
|
121
|
+
.sort((a, b) => a.subject.localeCompare(b.subject));
|
|
122
|
+
const selected = mapping?.linkState === 'unlinked' ? mapping.defaultBillingOwnerSubject : undefined;
|
|
123
|
+
organizations.push({
|
|
124
|
+
org: org.slug,
|
|
125
|
+
ownerCandidates: owners,
|
|
126
|
+
...(selected !== undefined ? { mappedOwnerSubject: selected } : {}),
|
|
127
|
+
...(mapping?.linkState === 'unlinked' ? { productionApps: mapping.productionApps } : {}),
|
|
128
|
+
});
|
|
129
|
+
if (mapping === undefined) {
|
|
130
|
+
blockers.push({
|
|
131
|
+
code: 'owner_mapping_required',
|
|
132
|
+
org: org.slug,
|
|
133
|
+
message: 'an operator must explicitly select the organization home Free owner',
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (mapping.linkState !== 'unlinked') {
|
|
138
|
+
blockers.push({
|
|
139
|
+
code: 'linked_organization_not_linked',
|
|
140
|
+
org: org.slug,
|
|
141
|
+
message: 'linked mapping targets an organization without an active billing-account link',
|
|
142
|
+
});
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const selectedSubject = mapping.defaultBillingOwnerSubject;
|
|
146
|
+
const selectedOwner = owners.find((owner) => owner.subject === selectedSubject);
|
|
147
|
+
if (selectedOwner === undefined) {
|
|
148
|
+
blockers.push({
|
|
149
|
+
code: owners.length === 0 ? 'owner_subject_unknown' : 'owner_not_org_owner',
|
|
150
|
+
org: org.slug,
|
|
151
|
+
message: 'mapped subject is not a current organization owner',
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
normalizeBillingIdentity({
|
|
157
|
+
identityIssuer: GOOGLE_CONTROL_PLANE_ISSUER,
|
|
158
|
+
subject: selectedOwner.subject,
|
|
159
|
+
});
|
|
160
|
+
normalizeBillingEmail(selectedOwner.email);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
blockers.push({
|
|
164
|
+
code: 'owner_billing_identity_invalid',
|
|
165
|
+
org: org.slug,
|
|
166
|
+
message: 'mapped organization owner cannot provision a billing account',
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const validProductionApps = await validateProductionApps(org.slug, mapping.productionApps, inventory, blockers);
|
|
171
|
+
if (!validProductionApps)
|
|
172
|
+
continue;
|
|
173
|
+
const existingDefault = await store.getDefaultBillingAccount({
|
|
174
|
+
identityIssuer: GOOGLE_CONTROL_PLANE_ISSUER,
|
|
175
|
+
subject: selectedSubject,
|
|
176
|
+
});
|
|
177
|
+
addToFundingSet(fundingSets, existingDefault === undefined
|
|
178
|
+
? {
|
|
179
|
+
kind: 'proposed_default',
|
|
180
|
+
identityIssuer: GOOGLE_CONTROL_PLANE_ISSUER,
|
|
181
|
+
subject: selectedSubject,
|
|
182
|
+
}
|
|
183
|
+
: { kind: 'existing', billingAccountId: existingDefault.id }, org.slug, mapping.productionApps);
|
|
184
|
+
}
|
|
185
|
+
for (const mapping of mappings) {
|
|
186
|
+
if (knownOrgs.has(mapping.org))
|
|
187
|
+
continue;
|
|
188
|
+
blockers.push({
|
|
189
|
+
code: 'organization_not_found',
|
|
190
|
+
org: mapping.org,
|
|
191
|
+
message: 'mapping references an unknown organization',
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
schemaVersion: 1,
|
|
196
|
+
ready: blockers.length === 0 &&
|
|
197
|
+
[...fundingSets.values()].every((set) => set.missingProductionClassifications.length === 0),
|
|
198
|
+
organizations: organizations.sort((a, b) => a.org.localeCompare(b.org)),
|
|
199
|
+
linkedOrganizations: linkedOrganizations.sort((a, b) => a.org.localeCompare(b.org)),
|
|
200
|
+
fundingSets: [...fundingSets.values()]
|
|
201
|
+
.map(({ destination, organizations: orgs, productionApps, missingProductionClassifications, }) => ({
|
|
202
|
+
destination,
|
|
203
|
+
organizations: orgs.sort(),
|
|
204
|
+
productionApps: productionApps.sort((a, b) => a.org.localeCompare(b.org) ||
|
|
205
|
+
a.app.localeCompare(b.app) ||
|
|
206
|
+
a.createdAt.localeCompare(b.createdAt)),
|
|
207
|
+
missingProductionClassifications: missingProductionClassifications.sort(),
|
|
208
|
+
}))
|
|
209
|
+
.sort((a, b) => fundingDestinationKey(a.destination).localeCompare(fundingDestinationKey(b.destination))),
|
|
210
|
+
blockers: blockers.sort((a, b) => a.org.localeCompare(b.org) || a.code.localeCompare(b.code)),
|
|
211
|
+
grantPolicy: {
|
|
212
|
+
durationDays: 90,
|
|
213
|
+
startsAt: 'billing_enforcement_cutover',
|
|
214
|
+
expiresAt: null,
|
|
215
|
+
eligibility: 'account_cohort_above_capacity',
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
async function validateProductionApps(org, productionApps, inventory, blockers) {
|
|
220
|
+
let valid = true;
|
|
221
|
+
const appSlugs = new Set();
|
|
222
|
+
for (const app of productionApps) {
|
|
223
|
+
if (appSlugs.has(app.app)) {
|
|
224
|
+
blockers.push({
|
|
225
|
+
code: 'duplicate_production_app',
|
|
226
|
+
org,
|
|
227
|
+
message: `production app ${app.app} appears more than once in the classification`,
|
|
228
|
+
});
|
|
229
|
+
valid = false;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
appSlugs.add(app.app);
|
|
233
|
+
const current = await inventory?.getAppIdentity(org, app.app);
|
|
234
|
+
if (current?.createdAt !== app.createdAt) {
|
|
235
|
+
blockers.push({
|
|
236
|
+
code: 'production_app_not_found',
|
|
237
|
+
org,
|
|
238
|
+
message: `production app identity ${app.app}@${app.createdAt} does not exist`,
|
|
239
|
+
});
|
|
240
|
+
valid = false;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (!current.active || current.archivedAt !== undefined) {
|
|
244
|
+
blockers.push({
|
|
245
|
+
code: 'production_app_not_active',
|
|
246
|
+
org,
|
|
247
|
+
message: `production app identity ${app.app}@${app.createdAt} is not active`,
|
|
248
|
+
});
|
|
249
|
+
valid = false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return valid;
|
|
253
|
+
}
|
|
254
|
+
function addToFundingSet(sets, destination, org, productionApps) {
|
|
255
|
+
const key = fundingDestinationKey(destination);
|
|
256
|
+
const current = sets.get(key) ?? {
|
|
257
|
+
destination,
|
|
258
|
+
organizations: [],
|
|
259
|
+
productionApps: [],
|
|
260
|
+
missingProductionClassifications: [],
|
|
261
|
+
};
|
|
262
|
+
current.organizations.push(org);
|
|
263
|
+
current.productionApps.push(...productionApps.map((app) => ({ org, ...app })));
|
|
264
|
+
sets.set(key, current);
|
|
265
|
+
}
|
|
266
|
+
function addMissingFundingSet(sets, destination, org) {
|
|
267
|
+
const key = fundingDestinationKey(destination);
|
|
268
|
+
const current = sets.get(key) ?? {
|
|
269
|
+
destination,
|
|
270
|
+
organizations: [],
|
|
271
|
+
productionApps: [],
|
|
272
|
+
missingProductionClassifications: [],
|
|
273
|
+
};
|
|
274
|
+
current.organizations.push(org);
|
|
275
|
+
current.missingProductionClassifications.push(org);
|
|
276
|
+
sets.set(key, current);
|
|
277
|
+
}
|
|
278
|
+
function fundingDestinationKey(destination) {
|
|
279
|
+
return destination.kind === 'existing'
|
|
280
|
+
? `existing:${destination.billingAccountId}`
|
|
281
|
+
: `proposed:${destination.identityIssuer}:${destination.subject}`;
|
|
282
|
+
}
|
|
283
|
+
function isValidBillingAccountId(value) {
|
|
284
|
+
try {
|
|
285
|
+
validateBillingAccountId(value);
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function isValidSlug(kind, value) {
|
|
293
|
+
try {
|
|
294
|
+
validateSlug(kind, value);
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/billing/migration.ts"],"names":[],"mappings":"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"}
|