@twin.org/node-core 0.0.3-next.52 → 0.0.3-next.54

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 (72) hide show
  1. package/dist/es/builders/engineEnvBuilder.js +20 -39
  2. package/dist/es/builders/engineEnvBuilder.js.map +1 -1
  3. package/dist/es/builders/engineServerEnvBuilder.js +42 -30
  4. package/dist/es/builders/engineServerEnvBuilder.js.map +1 -1
  5. package/dist/es/cli.js +6 -2
  6. package/dist/es/cli.js.map +1 -1
  7. package/dist/es/commands/bootstrapLegacy.js +204 -102
  8. package/dist/es/commands/bootstrapLegacy.js.map +1 -1
  9. package/dist/es/commands/identityCreate.js +52 -3
  10. package/dist/es/commands/identityCreate.js.map +1 -1
  11. package/dist/es/commands/identityImports.js +1 -0
  12. package/dist/es/commands/identityImports.js.map +1 -1
  13. package/dist/es/commands/identityVerifiableCredentialCreate.js +1 -0
  14. package/dist/es/commands/identityVerifiableCredentialCreate.js.map +1 -1
  15. package/dist/es/commands/identityVerificationMethodCreate.js +14 -11
  16. package/dist/es/commands/identityVerificationMethodCreate.js.map +1 -1
  17. package/dist/es/commands/identityVerificationMethodImport.js +1 -0
  18. package/dist/es/commands/identityVerificationMethodImport.js.map +1 -1
  19. package/dist/es/commands/nodeSetIdentity.js +5 -0
  20. package/dist/es/commands/nodeSetIdentity.js.map +1 -1
  21. package/dist/es/commands/removeTenantOrgAlias.js +81 -0
  22. package/dist/es/commands/removeTenantOrgAlias.js.map +1 -0
  23. package/dist/es/commands/setNodeOrgId.js +60 -0
  24. package/dist/es/commands/setNodeOrgId.js.map +1 -0
  25. package/dist/es/commands/setTenantOrgId.js +158 -0
  26. package/dist/es/commands/setTenantOrgId.js.map +1 -0
  27. package/dist/es/commands/tenantCreate.js +41 -7
  28. package/dist/es/commands/tenantCreate.js.map +1 -1
  29. package/dist/es/commands/vaultKeyCreate.js +1 -0
  30. package/dist/es/commands/vaultKeyCreate.js.map +1 -1
  31. package/dist/es/commands/vaultKeyImport.js +1 -0
  32. package/dist/es/commands/vaultKeyImport.js.map +1 -1
  33. package/dist/es/defaults.js +1 -3
  34. package/dist/es/defaults.js.map +1 -1
  35. package/dist/es/models/ICliCommandDefinition.js.map +1 -1
  36. package/dist/es/models/IEngineEnvironmentVariables.js.map +1 -1
  37. package/dist/es/models/IEngineServerEnvironmentVariables.js.map +1 -1
  38. package/dist/es/models/INodeEngineState.js.map +1 -1
  39. package/dist/es/node.js +2 -2
  40. package/dist/es/node.js.map +1 -1
  41. package/dist/es/start.js +76 -14
  42. package/dist/es/start.js.map +1 -1
  43. package/dist/es/utils.js +1 -1
  44. package/dist/es/utils.js.map +1 -1
  45. package/dist/types/builders/engineEnvBuilder.d.ts +2 -13
  46. package/dist/types/commands/bootstrapLegacy.d.ts +7 -7
  47. package/dist/types/commands/identityCreate.d.ts +6 -0
  48. package/dist/types/commands/removeTenantOrgAlias.d.ts +22 -0
  49. package/dist/types/commands/setNodeOrgId.d.ts +22 -0
  50. package/dist/types/commands/setTenantOrgId.d.ts +55 -0
  51. package/dist/types/commands/tenantCreate.d.ts +3 -0
  52. package/dist/types/defaults.d.ts +0 -1
  53. package/dist/types/models/ICliCommandDefinition.d.ts +5 -0
  54. package/dist/types/models/IEngineEnvironmentVariables.d.ts +8 -8
  55. package/dist/types/models/IEngineServerEnvironmentVariables.d.ts +4 -0
  56. package/dist/types/models/INodeEngineState.d.ts +5 -0
  57. package/docs/changelog.md +14 -0
  58. package/docs/reference/functions/buildEngineConfiguration.md +1 -7
  59. package/docs/reference/functions/isRightsManagementRequired.md +1 -1
  60. package/docs/reference/index.md +0 -2
  61. package/docs/reference/interfaces/ICliCommandDefinition.md +14 -0
  62. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +16 -16
  63. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +32 -24
  64. package/docs/reference/interfaces/INodeEngineState.md +9 -0
  65. package/docs/reference/interfaces/INodeEnvironmentVariables.md +36 -24
  66. package/locales/en.json +103 -38
  67. package/package.json +1 -1
  68. package/dist/es/commands/tenantToken.js +0 -97
  69. package/dist/es/commands/tenantToken.js.map +0 -1
  70. package/dist/types/commands/tenantToken.d.ts +0 -28
  71. package/docs/reference/functions/isUrlTransformerRequired.md +0 -20
  72. package/docs/reference/variables/URL_TRANSFORMER_ENCRYPTION_KEY_ID.md +0 -3
@@ -3,11 +3,9 @@ import { ContextIdKeys, ContextIdStore } from "@twin.org/context";
3
3
  import { Coerce, ComponentFactory, GeneralError, I18n, Is } from "@twin.org/core";
4
4
  import { identityCreate } from "./identityCreate.js";
5
5
  import { identityVerificationMethodCreate } from "./identityVerificationMethodCreate.js";
6
- import { nodeSetIdentity } from "./nodeSetIdentity.js";
7
6
  import { tenantCreate } from "./tenantCreate.js";
8
7
  import { userCreate } from "./userCreate.js";
9
8
  import { vaultKeyCreate } from "./vaultKeyCreate.js";
10
- import { isTrustRequired, isUrlTransformerRequired } from "../builders/engineEnvBuilder.js";
11
9
  const COMMAND_NAME = "bootstrap-legacy";
12
10
  /**
13
11
  * Get the command definition parameters.
@@ -19,6 +17,7 @@ export function getCommandDefinitionBootstrapLegacy(commandDefinitions) {
19
17
  description: I18n.formatMessage("node.cli.commands.bootstrap-legacy.description"),
20
18
  example: I18n.formatMessage("node.cli.commands.bootstrap-legacy.example"),
21
19
  requiresNodeIdentity: false,
20
+ requiresOrgIdentity: false,
22
21
  params: [
23
22
  {
24
23
  key: "env-prefix",
@@ -43,135 +42,158 @@ export function getCommandDefinitionBootstrapLegacy(commandDefinitions) {
43
42
  * @param params The parameters for the command.
44
43
  */
45
44
  export async function bootstrapLegacy(engineCore, envVars, params) {
46
- const features = (envVars.features ?? "")
45
+ const features = (envVars.features ?? "admin-user,wallet")
47
46
  .split(",")
48
47
  .map(f => f.trim())
49
48
  .filter(f => f.length > 0);
50
49
  const state = engineCore.getState();
51
- const requireWallet = features.includes("node-wallet");
50
+ const requireWallet = features.includes("wallet");
52
51
  const tenantEnabled = Coerce.boolean(envVars.tenantEnabled) ?? false;
53
- let nodeId = state.nodeId;
54
- let tenantId = tenantEnabled ? envVars.tenantId : undefined;
52
+ let nodeId = state.nodeId ?? envVars.nodeIdentity;
53
+ let organizationId = tenantEnabled ? undefined : state.nodeOrganizationId;
54
+ let tenant;
55
55
  if (features.length === 0) {
56
56
  throw new GeneralError("bootstrapLegacy", "noFeaturesEnabled");
57
57
  }
58
- if (features.includes("node-identity") && Is.empty(nodeId)) {
58
+ CLIDisplay.break();
59
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeIdentityCreate"));
60
+ const nodeIdentity = await identityCreate(engineCore, envVars, {
61
+ identity: nodeId,
62
+ mnemonic: envVars.nodeMnemonic,
63
+ fundWallet: requireWallet,
64
+ nodeId: true
65
+ });
66
+ nodeId = nodeIdentity.did;
67
+ CLIDisplay.break();
68
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeAuthKeyCreate"));
69
+ await vaultKeyCreate(engineCore, envVars, {
70
+ identity: nodeId,
71
+ keyType: "Ed25519",
72
+ keyId: envVars.authSigningKeyId,
73
+ overwriteMode: "skip"
74
+ });
75
+ // Always create the organisation identity first so it can be associated with
76
+ // the tenant (multi-tenant) or the node (single-tenant) immediately after.
77
+ // The trust verification method is always added to the organisation identity.
78
+ await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {
59
79
  CLIDisplay.break();
60
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeIdentityCreate"));
61
- const nodeIdentity = await identityCreate(engineCore, envVars, {
62
- identity: envVars.nodeIdentity,
63
- mnemonic: envVars.nodeMnemonic,
80
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.organisationCreate"));
81
+ if (tenantEnabled) {
82
+ const existingTenant = Is.stringValue(envVars.tenantId)
83
+ ? await resolveTenantById(engineCore, envVars.tenantId)
84
+ : await resolveDefaultTenant(engineCore);
85
+ organizationId = existingTenant?.organizationId;
86
+ }
87
+ const organisation = await identityCreate(engineCore, envVars, {
88
+ identity: organizationId ?? envVars.organizationIdentity,
89
+ mnemonic: envVars.organizationMnemonic,
64
90
  fundWallet: requireWallet
65
91
  });
66
- nodeId = nodeIdentity.did;
92
+ organizationId = organisation.did;
67
93
  CLIDisplay.break();
68
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeAuthKeyCreate"));
69
- await vaultKeyCreate(engineCore, envVars, {
70
- identity: nodeIdentity.did,
71
- keyType: "Ed25519",
72
- keyId: envVars.authSigningKeyId,
94
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.trustVerificationMethodCreate"));
95
+ await identityVerificationMethodCreate(engineCore, envVars, {
96
+ identity: organisation.did,
97
+ verificationMethodType: "assertionMethod",
98
+ verificationMethodId: envVars.trustVerificationMethodId,
73
99
  overwriteMode: "skip"
74
100
  });
75
- if (isTrustRequired(envVars)) {
101
+ if (Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) {
76
102
  CLIDisplay.break();
77
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.trustVerificationMethodCreate"));
103
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.blobStorageKeyCreate"));
104
+ await vaultKeyCreate(engineCore, envVars, {
105
+ identity: organizationId,
106
+ keyType: "ChaCha20Poly1305",
107
+ keyId: envVars.blobStorageEncryptionKeyId,
108
+ overwriteMode: "skip"
109
+ });
110
+ }
111
+ const defaultAttestationConnectorType = engineCore.getRegisteredInstanceTypeOptional("attestationConnector");
112
+ if (!Is.empty(defaultAttestationConnectorType)) {
113
+ CLIDisplay.break();
114
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.attestationMethodCreate"));
78
115
  await identityVerificationMethodCreate(engineCore, envVars, {
79
- identity: nodeIdentity.did,
116
+ identity: organizationId,
80
117
  verificationMethodType: "assertionMethod",
81
- verificationMethodId: envVars.trustVerificationMethodId,
118
+ verificationMethodId: envVars.attestationVerificationMethodId,
82
119
  overwriteMode: "skip"
83
120
  });
84
121
  }
85
- if (isUrlTransformerRequired(envVars)) {
122
+ const defaultImmutableProofComponentType = engineCore.getRegisteredInstanceTypeOptional("immutableProofComponent");
123
+ if (!Is.empty(defaultImmutableProofComponentType)) {
86
124
  CLIDisplay.break();
87
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.urlTransformParamKeyAdd"));
88
- await vaultKeyCreate(engineCore, envVars, {
89
- identity: nodeIdentity.did,
90
- keyType: "ChaCha20Poly1305",
91
- keyId: envVars.urlTransformerEncryptionKeyId
125
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.immutableProofMethodCreate"));
126
+ await identityVerificationMethodCreate(engineCore, envVars, {
127
+ identity: organizationId,
128
+ verificationMethodType: "assertionMethod",
129
+ verificationMethodId: envVars.immutableProofVerificationMethodId,
130
+ overwriteMode: "skip"
92
131
  });
93
132
  }
94
- CLIDisplay.break();
95
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeIdentitySet"));
96
- await nodeSetIdentity(engineCore, envVars, {
97
- identity: nodeId
98
- });
99
- if (tenantEnabled) {
100
- await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {
133
+ // In single-tenant mode, record the org DID in state so the node can resolve its
134
+ // organisation without a tenant lookup.
135
+ if (!tenantEnabled && !Is.stringValue(state.nodeOrganizationId)) {
136
+ CLIDisplay.break();
137
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeOrganizationIdSet"));
138
+ state.nodeOrganizationId = organisation.did;
139
+ engineCore.setStateDirty();
140
+ CLIDisplay.done();
141
+ }
142
+ });
143
+ if (tenantEnabled) {
144
+ await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {
145
+ // Resolve an existing tenant so a re-run does not create a duplicate.
146
+ // When a specific tenant ID is configured, look it up directly;
147
+ // otherwise search for the first tenant labelled "Tenant".
148
+ if (Is.stringValue(envVars.tenantId)) {
149
+ tenant = await resolveTenantById(engineCore, envVars.tenantId);
150
+ }
151
+ else {
152
+ tenant = await resolveDefaultTenant(engineCore);
153
+ }
154
+ // Still empty so create a new tenant for the node and associate it with the organisation.
155
+ if (Is.empty(tenant)) {
101
156
  CLIDisplay.break();
102
157
  CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.nodeTenantCreate"));
103
158
  const tenantDetails = await tenantCreate(engineCore, envVars, {
104
159
  tenantId: envVars.tenantId,
105
160
  apiKey: envVars.tenantApiKey,
106
- label: "Node"
161
+ label: "Tenant",
162
+ organizationId
107
163
  });
108
- tenantId = tenantDetails.tenantId;
109
- });
110
- }
111
- }
112
- else if (tenantEnabled && Is.empty(tenantId) && Is.stringValue(nodeId)) {
113
- await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {
114
- tenantId = await resolveBootstrapTenantId(engineCore);
164
+ tenant = {
165
+ id: tenantDetails.tenantId,
166
+ organizationId: organizationId ?? tenantDetails.organizationId ?? ""
167
+ };
168
+ }
115
169
  });
116
170
  }
117
- if (features.includes("node-admin-user")) {
118
- await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenantId }, async () => {
119
- CLIDisplay.break();
120
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.organisationCreate"));
121
- const organisation = await identityCreate(engineCore, envVars, {
122
- identity: envVars.organizationIdentity,
123
- mnemonic: envVars.organizationMnemonic,
124
- fundWallet: requireWallet
125
- });
126
- if (Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) {
127
- CLIDisplay.break();
128
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.blobStorageKeyCreate"));
129
- await vaultKeyCreate(engineCore, envVars, {
130
- identity: organisation.did,
131
- keyType: "ChaCha20Poly1305",
132
- keyId: envVars.blobStorageEncryptionKeyId,
133
- overwriteMode: "skip"
134
- });
135
- }
136
- const defaultAttestationConnectorType = engineCore.getRegisteredInstanceTypeOptional("attestationConnector");
137
- if (!Is.empty(defaultAttestationConnectorType)) {
138
- CLIDisplay.break();
139
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.attestationMethodCreate"));
140
- await identityVerificationMethodCreate(engineCore, envVars, {
141
- identity: organisation.did,
142
- verificationMethodType: "assertionMethod",
143
- verificationMethodId: envVars.attestationVerificationMethodId,
144
- overwriteMode: "skip"
145
- });
146
- }
147
- const defaultImmutableProofComponentType = engineCore.getRegisteredInstanceTypeOptional("immutableProofComponent");
148
- if (!Is.empty(defaultImmutableProofComponentType)) {
171
+ if (features.includes("admin-user")) {
172
+ await ContextIdStore.run({ [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenant?.id }, async () => {
173
+ const orgDid = await resolveOrganizationDid(engineCore, tenantEnabled, tenant?.id);
174
+ const effectiveAdminEmail = envVars.adminUserName ?? `admin@${tenantEnabled ? "tenant" : "node"}`;
175
+ const adminUser = await resolveDefaultAdminUser(engineCore, effectiveAdminEmail);
176
+ let userDid = adminUser?.userIdentity;
177
+ if (Is.empty(adminUser)) {
149
178
  CLIDisplay.break();
150
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.immutableProofMethodCreate"));
151
- await identityVerificationMethodCreate(engineCore, envVars, {
152
- identity: organisation.did,
153
- verificationMethodType: "assertionMethod",
154
- verificationMethodId: envVars.immutableProofVerificationMethodId,
155
- overwriteMode: "skip"
179
+ CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.adminIdentityCreate"));
180
+ const result = await identityCreate(engineCore, envVars, {
181
+ identity: envVars.adminUserIdentity,
182
+ mnemonic: envVars.adminUserMnemonic,
183
+ controller: orgDid
156
184
  });
185
+ userDid = result.did;
157
186
  }
158
187
  CLIDisplay.break();
159
- CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.adminIdentityCreate"));
160
- const adminUserIdentity = await identityCreate(engineCore, envVars, {
161
- identity: envVars.adminUserIdentity,
162
- mnemonic: envVars.adminUserMnemonic,
163
- controller: organisation.did
164
- });
165
- CLIDisplay.break();
166
188
  CLIDisplay.section(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.adminUserCreate"));
167
189
  await userCreate(engineCore, envVars, {
168
- userIdentity: adminUserIdentity.did,
169
- organizationIdentity: organisation.did,
170
- tenantId,
171
- email: envVars.adminUserName ?? "admin@node",
190
+ userIdentity: userDid,
191
+ organizationIdentity: orgDid,
192
+ tenantId: tenant?.id,
193
+ email: envVars.adminUserName ?? `admin@${tenantEnabled ? "tenant" : "node"}`,
172
194
  password: envVars.adminUserPassword,
173
- scope: ["tenant-admin", "user-admin"].join(","),
174
- givenName: "Node",
195
+ scope: (tenantEnabled ? ["tenant-admin", "user-admin"] : ["user-admin"]).join(","),
196
+ givenName: tenantEnabled ? "Tenant" : "Node",
175
197
  familyName: "Admin",
176
198
  overwriteMode: "skip"
177
199
  });
@@ -179,30 +201,110 @@ export async function bootstrapLegacy(engineCore, envVars, params) {
179
201
  }
180
202
  }
181
203
  /**
182
- * Resolve an existing tenant id for re-bootstrap when multi-tenancy is enabled.
204
+ * Resolve the organisation DID from node state (single-tenant) or the tenant entry (multi-tenant).
205
+ * @param engineCore The engine core.
206
+ * @param tenantEnabled Whether multi-tenancy is enabled.
207
+ * @param tenantId The active tenant ID (multi-tenant only).
208
+ * @returns The organisation DID.
209
+ * @throws GeneralError if the organisation has not been associated yet.
210
+ * @internal
211
+ */
212
+ async function resolveOrganizationDid(engineCore, tenantEnabled, tenantId) {
213
+ if (tenantEnabled) {
214
+ if (Is.stringValue(tenantId)) {
215
+ const tenantAdminComponentType = engineCore.getRegisteredInstanceTypeOptional("tenantAdminComponent");
216
+ if (Is.stringValue(tenantAdminComponentType)) {
217
+ const tenantAdminComponent = ComponentFactory.get(tenantAdminComponentType);
218
+ const tenant = await tenantAdminComponent.get(tenantId);
219
+ if (Is.stringValue(tenant.organizationId)) {
220
+ return tenant.organizationId;
221
+ }
222
+ }
223
+ }
224
+ }
225
+ else {
226
+ const state = engineCore.getState();
227
+ if (Is.stringValue(state.nodeOrganizationId)) {
228
+ return state.nodeOrganizationId;
229
+ }
230
+ }
231
+ throw new GeneralError("bootstrapLegacy", "organizationNotSet");
232
+ }
233
+ /**
234
+ * Resolve the default tenant id for re-bootstrap when multi-tenancy is enabled.
183
235
  * @param engineCore The engine core.
184
236
  * @returns The tenant id if one exists in storage.
185
237
  * @internal
186
238
  */
187
- async function resolveBootstrapTenantId(engineCore) {
239
+ async function resolveDefaultTenant(engineCore) {
188
240
  const tenantAdminServiceComponentType = engineCore.getRegisteredInstanceTypeOptional("tenantAdminComponent");
189
241
  if (!Is.stringValue(tenantAdminServiceComponentType)) {
190
242
  return undefined;
191
243
  }
192
244
  const tenantAdminService = ComponentFactory.get(tenantAdminServiceComponentType);
193
245
  let cursor;
194
- let firstTenantId;
246
+ let firstTenant;
195
247
  do {
196
- const result = await tenantAdminService.query(["id", "label"], cursor);
197
- const nodeTenant = result.tenants.find(tenant => tenant.label === "Node");
248
+ const result = await tenantAdminService.query(undefined, ["id", "organizationId", "label"], cursor);
249
+ const nodeTenant = result.tenants.find(tenant => tenant.label === "Tenant");
198
250
  if (nodeTenant) {
199
- return nodeTenant.id;
251
+ return {
252
+ id: nodeTenant.id,
253
+ organizationId: nodeTenant.organizationId ?? ""
254
+ };
200
255
  }
201
- if (Is.empty(firstTenantId) && !Is.empty(result.tenants)) {
202
- firstTenantId = result.tenants[0]?.id;
256
+ if (Is.empty(firstTenant) && Is.arrayValue(result.tenants)) {
257
+ firstTenant = {
258
+ id: result.tenants[0].id,
259
+ organizationId: result.tenants[0].organizationId ?? ""
260
+ };
203
261
  }
204
262
  cursor = result.cursor;
205
263
  } while (Is.stringValue(cursor));
206
- return firstTenantId;
264
+ if (!Is.empty(firstTenant)) {
265
+ CLIDisplay.value(I18n.formatMessage("node.cli.commands.bootstrap-legacy.labels.tenantFallback"), firstTenant.id);
266
+ }
267
+ return firstTenant;
268
+ }
269
+ /**
270
+ * Resolve the admin user by email for idempotent re-bootstrap.
271
+ * @param engineCore The engine core.
272
+ * @param email The email address of the admin user to look up.
273
+ * @returns The admin user if one exists in storage.
274
+ * @internal
275
+ */
276
+ async function resolveDefaultAdminUser(engineCore, email) {
277
+ const defaultAuthenticationAdminComponentType = engineCore.getRegisteredInstanceType("authenticationAdminComponent");
278
+ const authenticationAdminComponent = ComponentFactory.get(defaultAuthenticationAdminComponentType);
279
+ try {
280
+ return await authenticationAdminComponent.get(email);
281
+ }
282
+ catch {
283
+ return undefined;
284
+ }
285
+ }
286
+ /**
287
+ * Resolve a tenant by its specific ID for idempotent re-bootstrap.
288
+ * @param engineCore The engine core.
289
+ * @param tenantId The tenant ID to look up.
290
+ * @returns The tenant if found, otherwise undefined.
291
+ * @internal
292
+ */
293
+ async function resolveTenantById(engineCore, tenantId) {
294
+ const tenantAdminServiceComponentType = engineCore.getRegisteredInstanceTypeOptional("tenantAdminComponent");
295
+ if (!Is.stringValue(tenantAdminServiceComponentType)) {
296
+ return undefined;
297
+ }
298
+ const tenantAdminService = ComponentFactory.get(tenantAdminServiceComponentType);
299
+ try {
300
+ const found = await tenantAdminService.get(tenantId);
301
+ return {
302
+ id: found.id,
303
+ organizationId: found.organizationId ?? ""
304
+ };
305
+ }
306
+ catch {
307
+ return undefined;
308
+ }
207
309
  }
208
310
  //# sourceMappingURL=bootstrapLegacy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrapLegacy.js","sourceRoot":"","sources":["../../../src/commands/bootstrapLegacy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantAdminComponent } from \"@twin.org/api-models\";\nimport { CLIDisplay } from \"@twin.org/cli-core\";\nimport { ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, GeneralError, I18n, Is } from \"@twin.org/core\";\nimport type { IEngineCore } from \"@twin.org/engine-models\";\nimport { identityCreate } from \"./identityCreate.js\";\nimport { identityVerificationMethodCreate } from \"./identityVerificationMethodCreate.js\";\nimport { nodeSetIdentity } from \"./nodeSetIdentity.js\";\nimport { tenantCreate } from \"./tenantCreate.js\";\nimport { userCreate } from \"./userCreate.js\";\nimport { vaultKeyCreate } from \"./vaultKeyCreate.js\";\nimport { isTrustRequired, isUrlTransformerRequired } from \"../builders/engineEnvBuilder.js\";\nimport type { ICliCommandDefinition } from \"../models/ICliCommandDefinition.js\";\nimport type { INodeEngineConfig } from \"../models/INodeEngineConfig.js\";\nimport type { INodeEngineState } from \"../models/INodeEngineState.js\";\nimport type { INodeEnvironmentVariables } from \"../models/INodeEnvironmentVariables.js\";\n\nconst COMMAND_NAME = \"bootstrap-legacy\";\n\n/**\n * Get the command definition parameters.\n * @param commandDefinitions The registered command definitions.\n */\nexport function getCommandDefinitionBootstrapLegacy(commandDefinitions: {\n\t[id: string]: ICliCommandDefinition;\n}): void {\n\tcommandDefinitions[COMMAND_NAME] = {\n\t\tcommand: COMMAND_NAME,\n\t\tdescription: I18n.formatMessage(\"node.cli.commands.bootstrap-legacy.description\"),\n\t\texample: I18n.formatMessage(\"node.cli.commands.bootstrap-legacy.example\"),\n\t\trequiresNodeIdentity: false,\n\t\tparams: [\n\t\t\t{\n\t\t\t\tkey: \"env-prefix\",\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: I18n.formatMessage(\n\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.params.env-prefix.description\"\n\t\t\t\t),\n\t\t\t\trequired: false\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"load-env\",\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: I18n.formatMessage(\n\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.params.load-env.description\"\n\t\t\t\t),\n\t\t\t\trequired: false\n\t\t\t}\n\t\t],\n\t\taction: async (engineCore, envVars, params) => bootstrapLegacy(engineCore, envVars, params)\n\t};\n}\n\n/**\n * Command for legacy bootstrap.\n * @param engineCore The engine core.\n * @param envVars The environment variables for the node.\n * @param params The parameters for the command.\n */\nexport async function bootstrapLegacy(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables & {\n\t\t/**\n\t\t * The features that are enabled on the node.\n\t\t * @default []\n\t\t */\n\t\tfeatures?: string;\n\n\t\t/**\n\t\t * The identity of the node which, if empty and node-identity feature is enabled it will be generated.\n\t\t */\n\t\tnodeIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the identity, if empty and node-identity feature is enabled it will be randomly generated.\n\t\t */\n\t\tnodeMnemonic?: string;\n\n\t\t/**\n\t\t * A tenant id to use as a default for the node.\n\t\t */\n\t\ttenantId?: string;\n\n\t\t/**\n\t\t * A tenant api key to use as a default for the node.\n\t\t */\n\t\ttenantApiKey?: string;\n\n\t\t/**\n\t\t * If the node-admin-user feature is enabled, this will be the organization of the user, if one is not provided it will be generated\n\t\t */\n\t\torganizationIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the organization, if empty and node-admin-user feature is enabled it will be randomly generated.\n\t\t */\n\t\torganizationMnemonic?: string;\n\n\t\t/**\n\t\t * If the node-admin-user feature is enabled, this will be the identity of the user, if one is not provided it will be generated\n\t\t */\n\t\tadminUserIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the admin user, if empty and node-admin-user feature is enabled it will be randomly generated.\n\t\t */\n\t\tadminUserMnemonic?: string;\n\n\t\t/**\n\t\t * If the node-admin-user feature is enabled, this will be the name of the user.\n\t\t * @default admin@node\n\t\t */\n\t\tadminUserName?: string;\n\n\t\t/**\n\t\t * If the node-admin-user feature is enabled, this will be the password of the user, if empty it will be randomly generated.\n\t\t */\n\t\tadminUserPassword?: string;\n\t},\n\tparams: {}\n): Promise<void> {\n\tconst features = (envVars.features ?? \"\")\n\t\t.split(\",\")\n\t\t.map(f => f.trim())\n\t\t.filter(f => f.length > 0);\n\n\tconst state = engineCore.getState();\n\tconst requireWallet = features.includes(\"node-wallet\");\n\tconst tenantEnabled = Coerce.boolean(envVars.tenantEnabled) ?? false;\n\tlet nodeId = state.nodeId;\n\tlet tenantId = tenantEnabled ? envVars.tenantId : undefined;\n\n\tif (features.length === 0) {\n\t\tthrow new GeneralError(\"bootstrapLegacy\", \"noFeaturesEnabled\");\n\t}\n\n\tif (features.includes(\"node-identity\") && Is.empty(nodeId)) {\n\t\tCLIDisplay.break();\n\t\tCLIDisplay.section(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeIdentityCreate\")\n\t\t);\n\n\t\tconst nodeIdentity = await identityCreate(engineCore, envVars, {\n\t\t\tidentity: envVars.nodeIdentity,\n\t\t\tmnemonic: envVars.nodeMnemonic,\n\t\t\tfundWallet: requireWallet\n\t\t});\n\n\t\tnodeId = nodeIdentity.did;\n\n\t\tCLIDisplay.break();\n\t\tCLIDisplay.section(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeAuthKeyCreate\")\n\t\t);\n\t\tawait vaultKeyCreate(engineCore, envVars, {\n\t\t\tidentity: nodeIdentity.did,\n\t\t\tkeyType: \"Ed25519\",\n\t\t\tkeyId: envVars.authSigningKeyId,\n\t\t\toverwriteMode: \"skip\"\n\t\t});\n\n\t\tif (isTrustRequired(envVars)) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\n\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.labels.trustVerificationMethodCreate\"\n\t\t\t\t)\n\t\t\t);\n\n\t\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\t\tidentity: nodeIdentity.did,\n\t\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\t\tverificationMethodId: envVars.trustVerificationMethodId,\n\t\t\t\toverwriteMode: \"skip\"\n\t\t\t});\n\t\t}\n\n\t\tif (isUrlTransformerRequired(envVars)) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.urlTransformParamKeyAdd\")\n\t\t\t);\n\t\t\tawait vaultKeyCreate(engineCore, envVars, {\n\t\t\t\tidentity: nodeIdentity.did,\n\t\t\t\tkeyType: \"ChaCha20Poly1305\",\n\t\t\t\tkeyId: envVars.urlTransformerEncryptionKeyId\n\t\t\t});\n\t\t}\n\n\t\tCLIDisplay.break();\n\t\tCLIDisplay.section(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeIdentitySet\")\n\t\t);\n\t\tawait nodeSetIdentity(engineCore, envVars, {\n\t\t\tidentity: nodeId\n\t\t});\n\n\t\tif (tenantEnabled) {\n\t\t\tawait ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeTenantCreate\")\n\t\t\t\t);\n\t\t\t\tconst tenantDetails = await tenantCreate(engineCore, envVars, {\n\t\t\t\t\ttenantId: envVars.tenantId,\n\t\t\t\t\tapiKey: envVars.tenantApiKey,\n\t\t\t\t\tlabel: \"Node\"\n\t\t\t\t});\n\n\t\t\t\ttenantId = tenantDetails.tenantId;\n\t\t\t});\n\t\t}\n\t} else if (tenantEnabled && Is.empty(tenantId) && Is.stringValue(nodeId)) {\n\t\tawait ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {\n\t\t\ttenantId = await resolveBootstrapTenantId(engineCore);\n\t\t});\n\t}\n\n\tif (features.includes(\"node-admin-user\")) {\n\t\tawait ContextIdStore.run(\n\t\t\t{ [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenantId },\n\t\t\tasync () => {\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.organisationCreate\")\n\t\t\t\t);\n\t\t\t\tconst organisation = await identityCreate(engineCore, envVars, {\n\t\t\t\t\tidentity: envVars.organizationIdentity,\n\t\t\t\t\tmnemonic: envVars.organizationMnemonic,\n\t\t\t\t\tfundWallet: requireWallet\n\t\t\t\t});\n\n\t\t\t\tif (Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) {\n\t\t\t\t\tCLIDisplay.break();\n\t\t\t\t\tCLIDisplay.section(\n\t\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.blobStorageKeyCreate\")\n\t\t\t\t\t);\n\t\t\t\t\tawait vaultKeyCreate(engineCore, envVars, {\n\t\t\t\t\t\tidentity: organisation.did,\n\t\t\t\t\t\tkeyType: \"ChaCha20Poly1305\",\n\t\t\t\t\t\tkeyId: envVars.blobStorageEncryptionKeyId,\n\t\t\t\t\t\toverwriteMode: \"skip\"\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst defaultAttestationConnectorType =\n\t\t\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"attestationConnector\");\n\t\t\t\tif (!Is.empty(defaultAttestationConnectorType)) {\n\t\t\t\t\tCLIDisplay.break();\n\t\t\t\t\tCLIDisplay.section(\n\t\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.attestationMethodCreate\")\n\t\t\t\t\t);\n\t\t\t\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\t\t\t\tidentity: organisation.did,\n\t\t\t\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\t\t\t\tverificationMethodId: envVars.attestationVerificationMethodId,\n\t\t\t\t\t\toverwriteMode: \"skip\"\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst defaultImmutableProofComponentType =\n\t\t\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"immutableProofComponent\");\n\n\t\t\t\tif (!Is.empty(defaultImmutableProofComponentType)) {\n\t\t\t\t\tCLIDisplay.break();\n\t\t\t\t\tCLIDisplay.section(\n\t\t\t\t\t\tI18n.formatMessage(\n\t\t\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.labels.immutableProofMethodCreate\"\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\t\t\t\tidentity: organisation.did,\n\t\t\t\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\t\t\t\tverificationMethodId: envVars.immutableProofVerificationMethodId,\n\t\t\t\t\t\toverwriteMode: \"skip\"\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.adminIdentityCreate\")\n\t\t\t\t);\n\t\t\t\tconst adminUserIdentity = await identityCreate(engineCore, envVars, {\n\t\t\t\t\tidentity: envVars.adminUserIdentity,\n\t\t\t\t\tmnemonic: envVars.adminUserMnemonic,\n\t\t\t\t\tcontroller: organisation.did\n\t\t\t\t});\n\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.adminUserCreate\")\n\t\t\t\t);\n\t\t\t\tawait userCreate(engineCore, envVars, {\n\t\t\t\t\tuserIdentity: adminUserIdentity.did,\n\t\t\t\t\torganizationIdentity: organisation.did,\n\t\t\t\t\ttenantId,\n\t\t\t\t\temail: envVars.adminUserName ?? \"admin@node\",\n\t\t\t\t\tpassword: envVars.adminUserPassword,\n\t\t\t\t\tscope: [\"tenant-admin\", \"user-admin\"].join(\",\"),\n\t\t\t\t\tgivenName: \"Node\",\n\t\t\t\t\tfamilyName: \"Admin\",\n\t\t\t\t\toverwriteMode: \"skip\"\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\t}\n}\n\n/**\n * Resolve an existing tenant id for re-bootstrap when multi-tenancy is enabled.\n * @param engineCore The engine core.\n * @returns The tenant id if one exists in storage.\n * @internal\n */\nasync function resolveBootstrapTenantId(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>\n): Promise<string | undefined> {\n\tconst tenantAdminServiceComponentType =\n\t\tengineCore.getRegisteredInstanceTypeOptional(\"tenantAdminComponent\");\n\n\tif (!Is.stringValue(tenantAdminServiceComponentType)) {\n\t\treturn undefined;\n\t}\n\n\tconst tenantAdminService = ComponentFactory.get<ITenantAdminComponent>(\n\t\ttenantAdminServiceComponentType\n\t);\n\n\tlet cursor: string | undefined;\n\tlet firstTenantId: string | undefined;\n\n\tdo {\n\t\tconst result = await tenantAdminService.query([\"id\", \"label\"], cursor);\n\t\tconst nodeTenant = result.tenants.find(tenant => tenant.label === \"Node\");\n\t\tif (nodeTenant) {\n\t\t\treturn nodeTenant.id;\n\t\t}\n\n\t\tif (Is.empty(firstTenantId) && !Is.empty(result.tenants)) {\n\t\t\tfirstTenantId = result.tenants[0]?.id;\n\t\t}\n\n\t\tcursor = result.cursor;\n\t} while (Is.stringValue(cursor));\n\n\treturn firstTenantId;\n}\n"]}
1
+ {"version":3,"file":"bootstrapLegacy.js","sourceRoot":"","sources":["../../../src/commands/bootstrapLegacy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMrD,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,mCAAmC,CAAC,kBAEnD;IACA,kBAAkB,CAAC,YAAY,CAAC,GAAG;QAClC,OAAO,EAAE,YAAY;QACrB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,gDAAgD,CAAC;QACjF,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,4CAA4C,CAAC;QACzE,oBAAoB,EAAE,KAAK;QAC3B,mBAAmB,EAAE,KAAK;QAC1B,MAAM,EAAE;YACP;gBACC,GAAG,EAAE,YAAY;gBACjB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,IAAI,CAAC,aAAa,CAC9B,kEAAkE,CAClE;gBACD,QAAQ,EAAE,KAAK;aACf;YACD;gBACC,GAAG,EAAE,UAAU;gBACf,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,IAAI,CAAC,aAAa,CAC9B,gEAAgE,CAChE;gBACD,QAAQ,EAAE,KAAK;aACf;SACD;QACD,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC;KAC3F,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,UAA4D,EAC5D,OAyDC,EACD,MAAU;IAEV,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,mBAAmB,CAAC;SACxD,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE5B,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC;IACrE,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAClD,IAAI,cAAc,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;IAC1E,IAAI,MAA0D,CAAC;IAE/D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IAChE,CAAC;IAED,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,8DAA8D,CAAC,CAClF,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE;QAC9D,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,UAAU,EAAE,aAAa;QACzB,MAAM,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC;IAE1B,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,6DAA6D,CAAC,CACjF,CAAC;IACF,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE;QACzC,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,OAAO,CAAC,gBAAgB;QAC/B,aAAa,EAAE,MAAM;KACrB,CAAC,CAAC;IAEH,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,MAAM,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,EAAE;QACrE,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,8DAA8D,CAAC,CAClF,CAAC;QAEF,IAAI,aAAa,EAAE,CAAC;YACnB,MAAM,cAAc,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtD,CAAC,CAAC,MAAM,iBAAiB,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC;gBACvD,CAAC,CAAC,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;YAC1C,cAAc,GAAG,cAAc,EAAE,cAAc,CAAC;QACjD,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE;YAC9D,QAAQ,EAAE,cAAc,IAAI,OAAO,CAAC,oBAAoB;YACxD,QAAQ,EAAE,OAAO,CAAC,oBAAoB;YACtC,UAAU,EAAE,aAAa;SACzB,CAAC,CAAC;QACH,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC;QAElC,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,yEAAyE,CAAC,CAC7F,CAAC;QACF,MAAM,gCAAgC,CAAC,UAAU,EAAE,OAAO,EAAE;YAC3D,QAAQ,EAAE,YAAY,CAAC,GAAG;YAC1B,sBAAsB,EAAE,iBAAiB;YACzC,oBAAoB,EAAE,OAAO,CAAC,yBAAyB;YACvD,aAAa,EAAE,MAAM;SACrB,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,2BAA2B,CAAC,IAAI,KAAK,EAAE,CAAC;YAClE,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,gEAAgE,CAAC,CACpF,CAAC;YACF,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE;gBACzC,QAAQ,EAAE,cAAc;gBACxB,OAAO,EAAE,kBAAkB;gBAC3B,KAAK,EAAE,OAAO,CAAC,0BAA0B;gBACzC,aAAa,EAAE,MAAM;aACrB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,+BAA+B,GACpC,UAAU,CAAC,iCAAiC,CAAC,sBAAsB,CAAC,CAAC;QACtE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAAE,CAAC;YAChD,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,mEAAmE,CAAC,CACvF,CAAC;YACF,MAAM,gCAAgC,CAAC,UAAU,EAAE,OAAO,EAAE;gBAC3D,QAAQ,EAAE,cAAc;gBACxB,sBAAsB,EAAE,iBAAiB;gBACzC,oBAAoB,EAAE,OAAO,CAAC,+BAA+B;gBAC7D,aAAa,EAAE,MAAM;aACrB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,kCAAkC,GACvC,UAAU,CAAC,iCAAiC,CAAC,yBAAyB,CAAC,CAAC;QAEzE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,kCAAkC,CAAC,EAAE,CAAC;YACnD,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,sEAAsE,CAAC,CAC1F,CAAC;YACF,MAAM,gCAAgC,CAAC,UAAU,EAAE,OAAO,EAAE;gBAC3D,QAAQ,EAAE,cAAc;gBACxB,sBAAsB,EAAE,iBAAiB;gBACzC,oBAAoB,EAAE,OAAO,CAAC,kCAAkC;gBAChE,aAAa,EAAE,MAAM;aACrB,CAAC,CAAC;QACJ,CAAC;QAED,iFAAiF;QACjF,wCAAwC;QACxC,IAAI,CAAC,aAAa,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACjE,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,iEAAiE,CAAC,CACrF,CAAC;YACF,KAAK,CAAC,kBAAkB,GAAG,YAAY,CAAC,GAAG,CAAC;YAC5C,UAAU,CAAC,aAAa,EAAE,CAAC;YAC3B,UAAU,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,IAAI,aAAa,EAAE,CAAC;QACnB,MAAM,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,EAAE;YACrE,sEAAsE;YACtE,gEAAgE;YAChE,2DAA2D;YAC3D,IAAI,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,MAAM,iBAAiB,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACP,MAAM,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC;YAED,0FAA0F;YAC1F,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,UAAU,CAAC,KAAK,EAAE,CAAC;gBACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,4DAA4D,CAAC,CAChF,CAAC;gBACF,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,OAAO,EAAE;oBAC7D,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,MAAM,EAAE,OAAO,CAAC,YAAY;oBAC5B,KAAK,EAAE,QAAQ;oBACf,cAAc;iBACd,CAAC,CAAC;gBAEH,MAAM,GAAG;oBACR,EAAE,EAAE,aAAa,CAAC,QAAQ;oBAC1B,cAAc,EAAE,cAAc,IAAI,aAAa,CAAC,cAAc,IAAI,EAAE;iBACpE,CAAC;YACH,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,MAAM,cAAc,CAAC,GAAG,CACvB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EACpE,KAAK,IAAI,EAAE;YACV,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACnF,MAAM,mBAAmB,GACxB,OAAO,CAAC,aAAa,IAAI,SAAS,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YACvE,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;YACjF,IAAI,OAAO,GAAG,SAAS,EAAE,YAAY,CAAC;YAEtC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzB,UAAU,CAAC,KAAK,EAAE,CAAC;gBACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,+DAA+D,CAAC,CACnF,CAAC;gBACF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE;oBACxD,QAAQ,EAAE,OAAO,CAAC,iBAAiB;oBACnC,QAAQ,EAAE,OAAO,CAAC,iBAAiB;oBACnC,UAAU,EAAE,MAAM;iBAClB,CAAC,CAAC;gBAEH,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;YACtB,CAAC;YAED,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,CACjB,IAAI,CAAC,aAAa,CAAC,2DAA2D,CAAC,CAC/E,CAAC;YACF,MAAM,UAAU,CAAC,UAAU,EAAE,OAAO,EAAE;gBACrC,YAAY,EAAE,OAAO;gBACrB,oBAAoB,EAAE,MAAM;gBAC5B,QAAQ,EAAE,MAAM,EAAE,EAAE;gBACpB,KAAK,EAAE,OAAO,CAAC,aAAa,IAAI,SAAS,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE;gBAC5E,QAAQ,EAAE,OAAO,CAAC,iBAAiB;gBACnC,KAAK,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAClF,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM;gBAC5C,UAAU,EAAE,OAAO;gBACnB,aAAa,EAAE,MAAM;aACrB,CAAC,CAAC;QACJ,CAAC,CACD,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,sBAAsB,CACpC,UAA4D,EAC5D,aAAsB,EACtB,QAA4B;IAE5B,IAAI,aAAa,EAAE,CAAC;QACnB,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,MAAM,wBAAwB,GAC7B,UAAU,CAAC,iCAAiC,CAAC,sBAAsB,CAAC,CAAC;YACtE,IAAI,EAAE,CAAC,WAAW,CAAC,wBAAwB,CAAC,EAAE,CAAC;gBAC9C,MAAM,oBAAoB,GACzB,gBAAgB,CAAC,GAAG,CAAwB,wBAAwB,CAAC,CAAC;gBACvE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACxD,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;oBAC3C,OAAO,MAAM,CAAC,cAAc,CAAC;gBAC9B,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;QACpC,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC,kBAAkB,CAAC;QACjC,CAAC;IACF,CAAC;IAED,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,oBAAoB,CAClC,UAA4D;IAE5D,MAAM,+BAA+B,GACpC,UAAU,CAAC,iCAAiC,CAAC,sBAAsB,CAAC,CAAC;IAEtE,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,+BAA+B,CAAC,EAAE,CAAC;QACtD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,GAAG,CAC9C,+BAA+B,CAC/B,CAAC;IAEF,IAAI,MAA0B,CAAC;IAC/B,IAAI,WAA+D,CAAC;IAEpE,GAAG,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAC5C,SAAS,EACT,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EACjC,MAAM,CACN,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;QAC5E,IAAI,UAAU,EAAE,CAAC;YAChB,OAAO;gBACN,EAAE,EAAE,UAAU,CAAC,EAAE;gBACjB,cAAc,EAAE,UAAU,CAAC,cAAc,IAAI,EAAE;aAC/C,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5D,WAAW,GAAG;gBACb,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;gBACxB,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,IAAI,EAAE;aACtD,CAAC;QACH,CAAC;QAED,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE;IAEjC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,UAAU,CAAC,KAAK,CACf,IAAI,CAAC,aAAa,CAAC,0DAA0D,CAAC,EAC9E,WAAW,CAAC,EAAE,CACd,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,uBAAuB,CACrC,UAA4D,EAC5D,KAAa;IAEb,MAAM,uCAAuC,GAAG,UAAU,CAAC,yBAAyB,CACnF,8BAA8B,CAC9B,CAAC;IACF,MAAM,4BAA4B,GAAG,gBAAgB,CAAC,GAAG,CACxD,uCAAuC,CACvC,CAAC;IAEF,IAAI,CAAC;QACJ,OAAO,MAAM,4BAA4B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,iBAAiB,CAC/B,UAA4D,EAC5D,QAAgB;IAEhB,MAAM,+BAA+B,GACpC,UAAU,CAAC,iCAAiC,CAAC,sBAAsB,CAAC,CAAC;IAEtE,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,+BAA+B,CAAC,EAAE,CAAC;QACtD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,GAAG,CAC9C,+BAA+B,CAC/B,CAAC;IAEF,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrD,OAAO;YACN,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,EAAE;SAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IAuthenticationAdminComponent } from \"@twin.org/api-auth-entity-storage-models\";\nimport type { ITenantAdminComponent } from \"@twin.org/api-models\";\nimport { CLIDisplay } from \"@twin.org/cli-core\";\nimport { ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, GeneralError, I18n, Is } from \"@twin.org/core\";\nimport type { IEngineCore } from \"@twin.org/engine-models\";\nimport { identityCreate } from \"./identityCreate.js\";\nimport { identityVerificationMethodCreate } from \"./identityVerificationMethodCreate.js\";\nimport { tenantCreate } from \"./tenantCreate.js\";\nimport { userCreate } from \"./userCreate.js\";\nimport { vaultKeyCreate } from \"./vaultKeyCreate.js\";\nimport type { ICliCommandDefinition } from \"../models/ICliCommandDefinition.js\";\nimport type { INodeEngineConfig } from \"../models/INodeEngineConfig.js\";\nimport type { INodeEngineState } from \"../models/INodeEngineState.js\";\nimport type { INodeEnvironmentVariables } from \"../models/INodeEnvironmentVariables.js\";\n\nconst COMMAND_NAME = \"bootstrap-legacy\";\n\n/**\n * Get the command definition parameters.\n * @param commandDefinitions The registered command definitions.\n */\nexport function getCommandDefinitionBootstrapLegacy(commandDefinitions: {\n\t[id: string]: ICliCommandDefinition;\n}): void {\n\tcommandDefinitions[COMMAND_NAME] = {\n\t\tcommand: COMMAND_NAME,\n\t\tdescription: I18n.formatMessage(\"node.cli.commands.bootstrap-legacy.description\"),\n\t\texample: I18n.formatMessage(\"node.cli.commands.bootstrap-legacy.example\"),\n\t\trequiresNodeIdentity: false,\n\t\trequiresOrgIdentity: false,\n\t\tparams: [\n\t\t\t{\n\t\t\t\tkey: \"env-prefix\",\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: I18n.formatMessage(\n\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.params.env-prefix.description\"\n\t\t\t\t),\n\t\t\t\trequired: false\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"load-env\",\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: I18n.formatMessage(\n\t\t\t\t\t\"node.cli.commands.bootstrap-legacy.params.load-env.description\"\n\t\t\t\t),\n\t\t\t\trequired: false\n\t\t\t}\n\t\t],\n\t\taction: async (engineCore, envVars, params) => bootstrapLegacy(engineCore, envVars, params)\n\t};\n}\n\n/**\n * Command for legacy bootstrap.\n * @param engineCore The engine core.\n * @param envVars The environment variables for the node.\n * @param params The parameters for the command.\n */\nexport async function bootstrapLegacy(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables & {\n\t\t/**\n\t\t * The features that are enabled on the node.\n\t\t * @default []\n\t\t */\n\t\tfeatures?: string;\n\n\t\t/**\n\t\t * The identity of the node which, if empty and node-identity feature is enabled it will be generated.\n\t\t */\n\t\tnodeIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the node identity, if empty it will be randomly generated.\n\t\t */\n\t\tnodeMnemonic?: string;\n\n\t\t/**\n\t\t * A tenant id to use as a default for the node.\n\t\t */\n\t\ttenantId?: string;\n\n\t\t/**\n\t\t * A tenant api key to use as a default for the node.\n\t\t */\n\t\ttenantApiKey?: string;\n\n\t\t/**\n\t\t * The organisation identity. If not provided it will be generated.\n\t\t */\n\t\torganizationIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the organisation identity, if empty it will be randomly generated.\n\t\t */\n\t\torganizationMnemonic?: string;\n\n\t\t/**\n\t\t * If the admin-user feature is enabled, this will be the identity of the user. If not provided it will be generated.\n\t\t */\n\t\tadminUserIdentity?: string;\n\n\t\t/**\n\t\t * The mnemonic for the admin user, if empty it will be randomly generated.\n\t\t */\n\t\tadminUserMnemonic?: string;\n\n\t\t/**\n\t\t * If the admin-user feature is enabled, this will be the name of the user.\n\t\t * @default admin@node\n\t\t */\n\t\tadminUserName?: string;\n\n\t\t/**\n\t\t * If the admin-user feature is enabled, this will be the password of the user. If empty it will be randomly generated.\n\t\t */\n\t\tadminUserPassword?: string;\n\t},\n\tparams: {}\n): Promise<void> {\n\tconst features = (envVars.features ?? \"admin-user,wallet\")\n\t\t.split(\",\")\n\t\t.map(f => f.trim())\n\t\t.filter(f => f.length > 0);\n\n\tconst state = engineCore.getState();\n\tconst requireWallet = features.includes(\"wallet\");\n\tconst tenantEnabled = Coerce.boolean(envVars.tenantEnabled) ?? false;\n\tlet nodeId = state.nodeId ?? envVars.nodeIdentity;\n\tlet organizationId = tenantEnabled ? undefined : state.nodeOrganizationId;\n\tlet tenant: { id: string; organizationId: string } | undefined;\n\n\tif (features.length === 0) {\n\t\tthrow new GeneralError(\"bootstrapLegacy\", \"noFeaturesEnabled\");\n\t}\n\n\tCLIDisplay.break();\n\tCLIDisplay.section(\n\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeIdentityCreate\")\n\t);\n\n\tconst nodeIdentity = await identityCreate(engineCore, envVars, {\n\t\tidentity: nodeId,\n\t\tmnemonic: envVars.nodeMnemonic,\n\t\tfundWallet: requireWallet,\n\t\tnodeId: true\n\t});\n\n\tnodeId = nodeIdentity.did;\n\n\tCLIDisplay.break();\n\tCLIDisplay.section(\n\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeAuthKeyCreate\")\n\t);\n\tawait vaultKeyCreate(engineCore, envVars, {\n\t\tidentity: nodeId,\n\t\tkeyType: \"Ed25519\",\n\t\tkeyId: envVars.authSigningKeyId,\n\t\toverwriteMode: \"skip\"\n\t});\n\n\t// Always create the organisation identity first so it can be associated with\n\t// the tenant (multi-tenant) or the node (single-tenant) immediately after.\n\t// The trust verification method is always added to the organisation identity.\n\tawait ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {\n\t\tCLIDisplay.break();\n\t\tCLIDisplay.section(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.organisationCreate\")\n\t\t);\n\n\t\tif (tenantEnabled) {\n\t\t\tconst existingTenant = Is.stringValue(envVars.tenantId)\n\t\t\t\t? await resolveTenantById(engineCore, envVars.tenantId)\n\t\t\t\t: await resolveDefaultTenant(engineCore);\n\t\t\torganizationId = existingTenant?.organizationId;\n\t\t}\n\n\t\tconst organisation = await identityCreate(engineCore, envVars, {\n\t\t\tidentity: organizationId ?? envVars.organizationIdentity,\n\t\t\tmnemonic: envVars.organizationMnemonic,\n\t\t\tfundWallet: requireWallet\n\t\t});\n\t\torganizationId = organisation.did;\n\n\t\tCLIDisplay.break();\n\t\tCLIDisplay.section(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.trustVerificationMethodCreate\")\n\t\t);\n\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\tidentity: organisation.did,\n\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\tverificationMethodId: envVars.trustVerificationMethodId,\n\t\t\toverwriteMode: \"skip\"\n\t\t});\n\n\t\tif (Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.blobStorageKeyCreate\")\n\t\t\t);\n\t\t\tawait vaultKeyCreate(engineCore, envVars, {\n\t\t\t\tidentity: organizationId,\n\t\t\t\tkeyType: \"ChaCha20Poly1305\",\n\t\t\t\tkeyId: envVars.blobStorageEncryptionKeyId,\n\t\t\t\toverwriteMode: \"skip\"\n\t\t\t});\n\t\t}\n\n\t\tconst defaultAttestationConnectorType =\n\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"attestationConnector\");\n\t\tif (!Is.empty(defaultAttestationConnectorType)) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.attestationMethodCreate\")\n\t\t\t);\n\t\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\t\tidentity: organizationId,\n\t\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\t\tverificationMethodId: envVars.attestationVerificationMethodId,\n\t\t\t\toverwriteMode: \"skip\"\n\t\t\t});\n\t\t}\n\n\t\tconst defaultImmutableProofComponentType =\n\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"immutableProofComponent\");\n\n\t\tif (!Is.empty(defaultImmutableProofComponentType)) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.immutableProofMethodCreate\")\n\t\t\t);\n\t\t\tawait identityVerificationMethodCreate(engineCore, envVars, {\n\t\t\t\tidentity: organizationId,\n\t\t\t\tverificationMethodType: \"assertionMethod\",\n\t\t\t\tverificationMethodId: envVars.immutableProofVerificationMethodId,\n\t\t\t\toverwriteMode: \"skip\"\n\t\t\t});\n\t\t}\n\n\t\t// In single-tenant mode, record the org DID in state so the node can resolve its\n\t\t// organisation without a tenant lookup.\n\t\tif (!tenantEnabled && !Is.stringValue(state.nodeOrganizationId)) {\n\t\t\tCLIDisplay.break();\n\t\t\tCLIDisplay.section(\n\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeOrganizationIdSet\")\n\t\t\t);\n\t\t\tstate.nodeOrganizationId = organisation.did;\n\t\t\tengineCore.setStateDirty();\n\t\t\tCLIDisplay.done();\n\t\t}\n\t});\n\n\tif (tenantEnabled) {\n\t\tawait ContextIdStore.run({ [ContextIdKeys.Node]: nodeId }, async () => {\n\t\t\t// Resolve an existing tenant so a re-run does not create a duplicate.\n\t\t\t// When a specific tenant ID is configured, look it up directly;\n\t\t\t// otherwise search for the first tenant labelled \"Tenant\".\n\t\t\tif (Is.stringValue(envVars.tenantId)) {\n\t\t\t\ttenant = await resolveTenantById(engineCore, envVars.tenantId);\n\t\t\t} else {\n\t\t\t\ttenant = await resolveDefaultTenant(engineCore);\n\t\t\t}\n\n\t\t\t// Still empty so create a new tenant for the node and associate it with the organisation.\n\t\t\tif (Is.empty(tenant)) {\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.nodeTenantCreate\")\n\t\t\t\t);\n\t\t\t\tconst tenantDetails = await tenantCreate(engineCore, envVars, {\n\t\t\t\t\ttenantId: envVars.tenantId,\n\t\t\t\t\tapiKey: envVars.tenantApiKey,\n\t\t\t\t\tlabel: \"Tenant\",\n\t\t\t\t\torganizationId\n\t\t\t\t});\n\n\t\t\t\ttenant = {\n\t\t\t\t\tid: tenantDetails.tenantId,\n\t\t\t\t\torganizationId: organizationId ?? tenantDetails.organizationId ?? \"\"\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\tif (features.includes(\"admin-user\")) {\n\t\tawait ContextIdStore.run(\n\t\t\t{ [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenant?.id },\n\t\t\tasync () => {\n\t\t\t\tconst orgDid = await resolveOrganizationDid(engineCore, tenantEnabled, tenant?.id);\n\t\t\t\tconst effectiveAdminEmail =\n\t\t\t\t\tenvVars.adminUserName ?? `admin@${tenantEnabled ? \"tenant\" : \"node\"}`;\n\t\t\t\tconst adminUser = await resolveDefaultAdminUser(engineCore, effectiveAdminEmail);\n\t\t\t\tlet userDid = adminUser?.userIdentity;\n\n\t\t\t\tif (Is.empty(adminUser)) {\n\t\t\t\t\tCLIDisplay.break();\n\t\t\t\t\tCLIDisplay.section(\n\t\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.adminIdentityCreate\")\n\t\t\t\t\t);\n\t\t\t\t\tconst result = await identityCreate(engineCore, envVars, {\n\t\t\t\t\t\tidentity: envVars.adminUserIdentity,\n\t\t\t\t\t\tmnemonic: envVars.adminUserMnemonic,\n\t\t\t\t\t\tcontroller: orgDid\n\t\t\t\t\t});\n\n\t\t\t\t\tuserDid = result.did;\n\t\t\t\t}\n\n\t\t\t\tCLIDisplay.break();\n\t\t\t\tCLIDisplay.section(\n\t\t\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.adminUserCreate\")\n\t\t\t\t);\n\t\t\t\tawait userCreate(engineCore, envVars, {\n\t\t\t\t\tuserIdentity: userDid,\n\t\t\t\t\torganizationIdentity: orgDid,\n\t\t\t\t\ttenantId: tenant?.id,\n\t\t\t\t\temail: envVars.adminUserName ?? `admin@${tenantEnabled ? \"tenant\" : \"node\"}`,\n\t\t\t\t\tpassword: envVars.adminUserPassword,\n\t\t\t\t\tscope: (tenantEnabled ? [\"tenant-admin\", \"user-admin\"] : [\"user-admin\"]).join(\",\"),\n\t\t\t\t\tgivenName: tenantEnabled ? \"Tenant\" : \"Node\",\n\t\t\t\t\tfamilyName: \"Admin\",\n\t\t\t\t\toverwriteMode: \"skip\"\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\t}\n}\n\n/**\n * Resolve the organisation DID from node state (single-tenant) or the tenant entry (multi-tenant).\n * @param engineCore The engine core.\n * @param tenantEnabled Whether multi-tenancy is enabled.\n * @param tenantId The active tenant ID (multi-tenant only).\n * @returns The organisation DID.\n * @throws GeneralError if the organisation has not been associated yet.\n * @internal\n */\nasync function resolveOrganizationDid(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>,\n\ttenantEnabled: boolean,\n\ttenantId: string | undefined\n): Promise<string> {\n\tif (tenantEnabled) {\n\t\tif (Is.stringValue(tenantId)) {\n\t\t\tconst tenantAdminComponentType =\n\t\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"tenantAdminComponent\");\n\t\t\tif (Is.stringValue(tenantAdminComponentType)) {\n\t\t\t\tconst tenantAdminComponent =\n\t\t\t\t\tComponentFactory.get<ITenantAdminComponent>(tenantAdminComponentType);\n\t\t\t\tconst tenant = await tenantAdminComponent.get(tenantId);\n\t\t\t\tif (Is.stringValue(tenant.organizationId)) {\n\t\t\t\t\treturn tenant.organizationId;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst state = engineCore.getState();\n\t\tif (Is.stringValue(state.nodeOrganizationId)) {\n\t\t\treturn state.nodeOrganizationId;\n\t\t}\n\t}\n\n\tthrow new GeneralError(\"bootstrapLegacy\", \"organizationNotSet\");\n}\n\n/**\n * Resolve the default tenant id for re-bootstrap when multi-tenancy is enabled.\n * @param engineCore The engine core.\n * @returns The tenant id if one exists in storage.\n * @internal\n */\nasync function resolveDefaultTenant(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>\n): Promise<{ id: string; organizationId: string } | undefined> {\n\tconst tenantAdminServiceComponentType =\n\t\tengineCore.getRegisteredInstanceTypeOptional(\"tenantAdminComponent\");\n\n\tif (!Is.stringValue(tenantAdminServiceComponentType)) {\n\t\treturn undefined;\n\t}\n\n\tconst tenantAdminService = ComponentFactory.get<ITenantAdminComponent>(\n\t\ttenantAdminServiceComponentType\n\t);\n\n\tlet cursor: string | undefined;\n\tlet firstTenant: { id: string; organizationId: string } | undefined;\n\n\tdo {\n\t\tconst result = await tenantAdminService.query(\n\t\t\tundefined,\n\t\t\t[\"id\", \"organizationId\", \"label\"],\n\t\t\tcursor\n\t\t);\n\t\tconst nodeTenant = result.tenants.find(tenant => tenant.label === \"Tenant\");\n\t\tif (nodeTenant) {\n\t\t\treturn {\n\t\t\t\tid: nodeTenant.id,\n\t\t\t\torganizationId: nodeTenant.organizationId ?? \"\"\n\t\t\t};\n\t\t}\n\n\t\tif (Is.empty(firstTenant) && Is.arrayValue(result.tenants)) {\n\t\t\tfirstTenant = {\n\t\t\t\tid: result.tenants[0].id,\n\t\t\t\torganizationId: result.tenants[0].organizationId ?? \"\"\n\t\t\t};\n\t\t}\n\n\t\tcursor = result.cursor;\n\t} while (Is.stringValue(cursor));\n\n\tif (!Is.empty(firstTenant)) {\n\t\tCLIDisplay.value(\n\t\t\tI18n.formatMessage(\"node.cli.commands.bootstrap-legacy.labels.tenantFallback\"),\n\t\t\tfirstTenant.id\n\t\t);\n\t}\n\n\treturn firstTenant;\n}\n\n/**\n * Resolve the admin user by email for idempotent re-bootstrap.\n * @param engineCore The engine core.\n * @param email The email address of the admin user to look up.\n * @returns The admin user if one exists in storage.\n * @internal\n */\nasync function resolveDefaultAdminUser(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>,\n\temail: string\n): Promise<{ email: string; userIdentity: string; organizationIdentity: string } | undefined> {\n\tconst defaultAuthenticationAdminComponentType = engineCore.getRegisteredInstanceType(\n\t\t\"authenticationAdminComponent\"\n\t);\n\tconst authenticationAdminComponent = ComponentFactory.get<IAuthenticationAdminComponent>(\n\t\tdefaultAuthenticationAdminComponentType\n\t);\n\n\ttry {\n\t\treturn await authenticationAdminComponent.get(email);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Resolve a tenant by its specific ID for idempotent re-bootstrap.\n * @param engineCore The engine core.\n * @param tenantId The tenant ID to look up.\n * @returns The tenant if found, otherwise undefined.\n * @internal\n */\nasync function resolveTenantById(\n\tengineCore: IEngineCore<INodeEngineConfig, INodeEngineState>,\n\ttenantId: string\n): Promise<{ id: string; organizationId: string } | undefined> {\n\tconst tenantAdminServiceComponentType =\n\t\tengineCore.getRegisteredInstanceTypeOptional(\"tenantAdminComponent\");\n\n\tif (!Is.stringValue(tenantAdminServiceComponentType)) {\n\t\treturn undefined;\n\t}\n\n\tconst tenantAdminService = ComponentFactory.get<ITenantAdminComponent>(\n\t\ttenantAdminServiceComponentType\n\t);\n\n\ttry {\n\t\tconst found = await tenantAdminService.get(tenantId);\n\t\treturn {\n\t\t\tid: found.id,\n\t\t\torganizationId: found.organizationId ?? \"\"\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -8,6 +8,8 @@ import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
8
8
  import { Did, IdentityConnectorFactory, IdentityResolverConnectorFactory } from "@twin.org/identity-models";
9
9
  import { VaultConnectorFactory } from "@twin.org/vault-models";
10
10
  import { WalletConnectorFactory } from "@twin.org/wallet-models";
11
+ import { nodeSetIdentity } from "./nodeSetIdentity.js";
12
+ import { applyOrganizationIdToTenant } from "./setTenantOrgId.js";
11
13
  const COMMAND_NAME = "identity-create";
12
14
  /**
13
15
  * Get the command definition parameters.
@@ -19,6 +21,7 @@ export function getCommandDefinitionIdentityCreate(commandDefinitions) {
19
21
  description: I18n.formatMessage("node.cli.commands.identity-create.description"),
20
22
  example: I18n.formatMessage("node.cli.commands.identity-create.example"),
21
23
  requiresNodeIdentity: false,
24
+ requiresOrgIdentity: false,
22
25
  params: [
23
26
  {
24
27
  key: "env-prefix",
@@ -77,6 +80,27 @@ export function getCommandDefinitionIdentityCreate(commandDefinitions) {
77
80
  type: "string",
78
81
  description: I18n.formatMessage("node.cli.commands.identity-create.params.output-env-prefix.description"),
79
82
  required: false
83
+ },
84
+ {
85
+ key: "node-id",
86
+ type: "boolean",
87
+ description: I18n.formatMessage("node.cli.commands.identity-create.params.node-id.description"),
88
+ required: false,
89
+ defaultValue: false
90
+ },
91
+ {
92
+ key: "node-organization-id",
93
+ type: "boolean",
94
+ description: I18n.formatMessage("node.cli.commands.identity-create.params.node-organization-id.description"),
95
+ required: false,
96
+ defaultValue: false
97
+ },
98
+ {
99
+ key: "tenant-organization-id",
100
+ type: "string",
101
+ extendedType: "hex(32)",
102
+ description: I18n.formatMessage("node.cli.commands.identity-create.params.tenant-organization-id.description"),
103
+ required: false
80
104
  }
81
105
  ],
82
106
  action: async (engineCore, envVars, params) => identityCreate(engineCore, envVars, params)
@@ -91,12 +115,21 @@ export function getCommandDefinitionIdentityCreate(commandDefinitions) {
91
115
  * @param params.identity The DID of the identity to create.
92
116
  * @param params.controller The controller DID for the identity.
93
117
  * @param params.fundWallet Whether to fund the wallet associated with the identity from a faucet.
118
+ * @param params.nodeId If true, set the created DID as the node identity.
119
+ * @param params.nodeOrganizationId If true, set the created DID as the node organization ID.
120
+ * @param params.tenantOrganizationId The tenant ID to set the created DID as the organization ID for.
94
121
  * @param params.outputJson The output .json file to store the command output.
95
122
  * @param params.outputEnv The output .env file to store the command output.
96
123
  * @param params.outputEnvPrefix The prefix to use for variables in the output .env file.
97
124
  * @returns The identity details.
98
125
  */
99
126
  export async function identityCreate(engineCore, envVars, params) {
127
+ const assignmentCount = (params.nodeId ? 1 : 0) +
128
+ (params.nodeOrganizationId ? 1 : 0) +
129
+ (Is.stringValue(params.tenantOrganizationId) ? 1 : 0);
130
+ if (assignmentCount > 1) {
131
+ throw new GeneralError("identityCreate", "onlyOneAssignmentOptionAllowed");
132
+ }
100
133
  let workingIdentity = params?.identity;
101
134
  let tempIdentity;
102
135
  if (!Is.stringValue(workingIdentity)) {
@@ -122,9 +155,25 @@ export async function identityCreate(engineCore, envVars, params) {
122
155
  await mnemonicFinalise(vaultConnector, tempIdentity, workingIdentity);
123
156
  await walletFinalise(engineCore, workingIdentity, walletAddress);
124
157
  }
125
- CLIDisplay.break();
126
- CLIDisplay.value(I18n.formatMessage("node.cli.commands.identity-create.labels.mnemonic"), mnemonicResult.mnemonic);
127
- CLIDisplay.value(I18n.formatMessage("node.cli.commands.identity-create.labels.did"), workingIdentity);
158
+ if (params.nodeId) {
159
+ await nodeSetIdentity(engineCore, envVars, { identity: workingIdentity });
160
+ }
161
+ if (params.nodeOrganizationId) {
162
+ if (Coerce.boolean(envVars.tenantEnabled)) {
163
+ throw new GeneralError("identityCreate", "nodeOrganizationIdNotAvailableInMultiTenantMode");
164
+ }
165
+ const state = engineCore.getState();
166
+ state.nodeOrganizationId = workingIdentity;
167
+ engineCore.setStateDirty();
168
+ }
169
+ if (Is.stringValue(params.tenantOrganizationId)) {
170
+ await applyOrganizationIdToTenant(engineCore, params.tenantOrganizationId, workingIdentity);
171
+ }
172
+ if (mnemonicStored) {
173
+ CLIDisplay.break();
174
+ CLIDisplay.value(I18n.formatMessage("node.cli.commands.identity-create.labels.mnemonic"), mnemonicResult.mnemonic);
175
+ CLIDisplay.value(I18n.formatMessage("node.cli.commands.identity-create.labels.did"), workingIdentity);
176
+ }
128
177
  if (Is.stringValue(envVars.iotaExplorerEndpoint) &&
129
178
  envVars.identityConnector === IdentityConnectorType.Iota) {
130
179
  const idParts = Did.parse(workingIdentity);