@calimero-network/mero-js 23.3.0 → 23.4.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.
@@ -210,6 +210,17 @@ export interface FoundNamespaceInput {
210
210
  * signed.
211
211
  */
212
212
  defaultCapabilities?: number;
213
+ /**
214
+ * The application the namespace runs, set right after founding. Without one
215
+ * a founded namespace targets no application, and no context can be created
216
+ * in it. Set through the relay with a delegated `TargetApplicationSet`, which
217
+ * core accepts only as a group's first application.
218
+ */
219
+ application?: {
220
+ applicationId: string;
221
+ package: string;
222
+ version: string;
223
+ };
213
224
  }
214
225
  /** A namespace founded through a relay. */
215
226
  export interface FoundedNamespace {
@@ -237,6 +248,14 @@ export interface FoundedNamespace {
237
248
  defaultCapabilitiesSet?: boolean;
238
249
  /** Why `defaultCapabilitiesSet` is `false`. */
239
250
  defaultCapabilitiesError?: string;
251
+ /**
252
+ * Present only when `application` was asked for: whether the namespace now
253
+ * runs it. `false` leaves it with no application; retry with
254
+ * `govern({ groupId: namespaceId, op: targetApplicationSetOp(application) })`.
255
+ */
256
+ applicationSet?: boolean;
257
+ /** Why `applicationSet` is `false`. */
258
+ applicationError?: string;
240
259
  }
241
260
  /** Where an accepted intent landed. */
242
261
  export interface IntentResult<T = unknown> {
@@ -31,7 +31,7 @@ import { signWarrant } from '../warrant/warrant.js';
31
31
  import { resolveSigner } from '../signer/signer.js';
32
32
  import { signCreationWarrant } from '../warrant/creation-warrant.js';
33
33
  import { signGovernanceWarrant } from '../warrant/governance-warrant.js';
34
- import { defaultCapabilitiesSetOp, foundedNamespaceId, namespaceCreatedOp, } from '../warrant/governance-op.js';
34
+ import { defaultCapabilitiesSetOp, targetApplicationSetOp, foundedNamespaceId, namespaceCreatedOp, } from '../warrant/governance-op.js';
35
35
  import { HTTPError } from '../http-client/web-client.js';
36
36
  import { fromHex, hex } from '../crypto/internal.js';
37
37
  /** How long a freshly minted warrant stays presentable, in seconds. */
@@ -351,6 +351,7 @@ export class RelayClient {
351
351
  const capabilitiesOp = input.defaultCapabilities === undefined
352
352
  ? undefined
353
353
  : defaultCapabilitiesSetOp(input.defaultCapabilities);
354
+ const applicationOp = input.application ? targetApplicationSetOp(input.application) : undefined;
354
355
  // Resolved before the nonce, so a misconfigured key burns none.
355
356
  const signer = await this.authorSigner();
356
357
  const nonce = await this.config.nonces.next();
@@ -371,23 +372,32 @@ export class RelayClient {
371
372
  teeEnabled: data.teeEnabled ?? false,
372
373
  ...(data.teeError ? { teeError: data.teeError } : {}),
373
374
  };
374
- if (!capabilitiesOp)
375
- return founded;
376
- // A second op, under its own warrant, on the namespace root: the founder is
377
- // its admin and the relay was seated to act for members, so it goes through
378
- // the ordinary `govern` path. The namespace exists whatever happens here, so
379
- // a failure is reported rather than thrown.
380
- try {
381
- await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
382
- return { ...founded, defaultCapabilitiesSet: true };
375
+ // Follow-up ops, each under its own warrant, on the namespace root: the
376
+ // founder is its admin and the relay was seated to act for members, so they
377
+ // go through the ordinary `govern` path. The namespace exists whatever
378
+ // happens here, so a failure is reported rather than thrown. The
379
+ // application first: without it the namespace can hold no context at all.
380
+ let result = founded;
381
+ const message = (err) => (err instanceof Error ? err.message : String(err));
382
+ if (applicationOp) {
383
+ try {
384
+ await this.govern({ groupId: founded.namespaceId, op: applicationOp });
385
+ result = { ...result, applicationSet: true };
386
+ }
387
+ catch (err) {
388
+ result = { ...result, applicationSet: false, applicationError: message(err) };
389
+ }
383
390
  }
384
- catch (err) {
385
- return {
386
- ...founded,
387
- defaultCapabilitiesSet: false,
388
- defaultCapabilitiesError: err instanceof Error ? err.message : String(err),
389
- };
391
+ if (capabilitiesOp) {
392
+ try {
393
+ await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
394
+ result = { ...result, defaultCapabilitiesSet: true };
395
+ }
396
+ catch (err) {
397
+ result = { ...result, defaultCapabilitiesSet: false, defaultCapabilitiesError: message(err) };
398
+ }
390
399
  }
400
+ return result;
391
401
  }
392
402
  async postGovernance(groupId, op, warrant) {
393
403
  const body = await this.json('POST', `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`, {
@@ -64,13 +64,22 @@ export declare function memberRoleSetOp(member: string, memberRole: GovernanceMe
64
64
  */
65
65
  export declare function createdSubgroupId(admin: string, parentId: string, restricted: boolean, salt: string): Promise<string>;
66
66
  /**
67
- * Set the group's default capability mask (`MemberCapabilities` bits, a `u32`),
68
- * the capabilities every member holds without a per-member grant. Needs admin.
67
+ * Choose the application a group runs (`GroupOp::TargetApplicationSet`), in
68
+ * its delegable form: `bytecode_id` is left for the relay to fill (32 zero
69
+ * bytes), resolved from `package@version` in the registry. The member signs
70
+ * the application id, package and version, so the relay can pick no other
71
+ * build; the application id binds package and signer, and every node checks
72
+ * the bundle's signature.
69
73
  *
70
- * The relay refuses any change to `CAN_AUTHOR_ON_BEHALF` (bit 9) through this
71
- * path, and no namespace starts with it in its default mask, so a mask that
72
- * sets it is refused here rather than burning a nonce on a certain 403.
74
+ * Through a relay this is accepted only as a group's FIRST application, on a
75
+ * group that targets none yet (a namespace an account founded). Moving an
76
+ * existing target is an upgrade, which never goes through a relay.
73
77
  */
78
+ export declare function targetApplicationSetOp(input: {
79
+ applicationId: string;
80
+ package: string;
81
+ version: string;
82
+ }): GovernanceOp;
74
83
  export declare function defaultCapabilitiesSetOp(capabilities: number): GovernanceOp;
75
84
  /** What a subgroup is created with. */
76
85
  export interface GroupCreatedInput {
@@ -38,6 +38,7 @@ const GROUP_OP = {
38
38
  MemberRoleSet: 4,
39
39
  MemberCapabilitySet: 5,
40
40
  DefaultCapabilitiesSet: 6,
41
+ TargetApplicationSet: 7,
41
42
  ContextDetached: 9,
42
43
  SubgroupVisibilitySet: 10,
43
44
  GroupMetadataSet: 11,
@@ -137,6 +138,31 @@ export async function createdSubgroupId(admin, parentId, restricted, salt) {
137
138
  * path, and no namespace starts with it in its default mask, so a mask that
138
139
  * sets it is refused here rather than burning a nonce on a certain 403.
139
140
  */
141
+ /** A borsh `String`: a u32 byte length, then the UTF-8 bytes. */
142
+ function borshString(value, what) {
143
+ if (value.length === 0)
144
+ throw new Error(`${what} must not be empty`);
145
+ const bytes = new TextEncoder().encode(value);
146
+ return concat(u32le(bytes.length), bytes);
147
+ }
148
+ /**
149
+ * Choose the application a group runs (`GroupOp::TargetApplicationSet`), in
150
+ * its delegable form: `bytecode_id` is left for the relay to fill (32 zero
151
+ * bytes), resolved from `package@version` in the registry. The member signs
152
+ * the application id, package and version, so the relay can pick no other
153
+ * build; the application id binds package and signer, and every node checks
154
+ * the bundle's signature.
155
+ *
156
+ * Through a relay this is accepted only as a group's FIRST application, on a
157
+ * group that targets none yet (a namespace an account founded). Moving an
158
+ * existing target is an upgrade, which never goes through a relay.
159
+ */
160
+ export function targetApplicationSetOp(input) {
161
+ return {
162
+ kind: 'group',
163
+ bytes: concat(tag(GROUP_OP.TargetApplicationSet), CLEARED_HASH, fromHex(input.applicationId, 'applicationId', 32), borshString(input.package, 'package'), borshString(input.version, 'version')),
164
+ };
165
+ }
140
166
  export function defaultCapabilitiesSetOp(capabilities) {
141
167
  if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
142
168
  throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
@@ -4,5 +4,5 @@ export { signCreationWarrant, parseCreationWarrant, creationInitHash, } from './
4
4
  export type { CreationWarrantInput, CreationWarrantFields, SignedCreationWarrant, } from './creation-warrant.js';
5
5
  export { signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, } from './governance-warrant.js';
6
6
  export type { GovernanceWarrantInput, GovernanceWarrantFields, } from './governance-warrant.js';
7
- export { memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from './governance-op.js';
7
+ export { memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, targetApplicationSetOp, foundedNamespaceId, } from './governance-op.js';
8
8
  export type { GovernanceOp, GovernanceOpKind, GovernanceMemberRole, GroupCreatedInput, SubgroupCreation, NamespaceCreatedInput, } from './governance-op.js';
@@ -2,4 +2,4 @@
2
2
  export { signWarrant, intentHash } from './warrant.js';
3
3
  export { signCreationWarrant, parseCreationWarrant, creationInitHash, } from './creation-warrant.js';
4
4
  export { signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, } from './governance-warrant.js';
5
- export { memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from './governance-op.js';
5
+ export { memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, targetApplicationSetOp, foundedNamespaceId, } from './governance-op.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calimero-network/mero-js",
3
- "version": "23.3.0",
3
+ "version": "23.4.1",
4
4
  "description": "Pure JavaScript SDK for Calimero",
5
5
  "type": "module",
6
6
  "exports": {