@calimero-network/agent-skills 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +137 -17
  2. package/SKILL.md +31 -28
  3. package/package.json +1 -1
  4. package/scripts/install.js +3 -3
  5. package/scripts/test.js +6 -15
  6. package/skills/calimero-abi-codegen/SKILL.md +121 -22
  7. package/skills/calimero-abi-codegen/references/abi-format.md +3 -5
  8. package/skills/calimero-abi-codegen/references/generated-output.md +12 -4
  9. package/skills/calimero-abi-codegen/rules/schema-version.md +11 -4
  10. package/skills/calimero-abi-codegen/rules/unique-names.md +2 -6
  11. package/skills/calimero-client-js/SKILL.md +126 -31
  12. package/skills/calimero-client-js/references/auth.md +18 -10
  13. package/skills/calimero-client-js/references/rpc-calls.md +15 -21
  14. package/skills/calimero-client-js/references/sso.md +9 -9
  15. package/skills/calimero-client-js/references/websocket-events.md +73 -92
  16. package/skills/calimero-client-js/rules/camelcase-api.md +10 -7
  17. package/skills/calimero-client-js/rules/token-refresh.md +11 -11
  18. package/skills/calimero-client-py/SKILL.md +25 -13
  19. package/skills/calimero-client-py/references/api.md +41 -43
  20. package/skills/calimero-client-py/references/auth.md +7 -7
  21. package/skills/calimero-client-py/rules/async-usage.md +27 -31
  22. package/skills/calimero-client-py/rules/stable-node-name.md +7 -7
  23. package/skills/calimero-core/SKILL.md +135 -0
  24. package/skills/calimero-core/references/architecture.md +101 -0
  25. package/skills/calimero-core/references/jsonrpc-protocol.md +192 -0
  26. package/skills/calimero-core/references/namespaces-groups.md +94 -0
  27. package/skills/calimero-core/references/storage-types.md +118 -0
  28. package/skills/calimero-core/references/websocket-events.md +142 -0
  29. package/skills/calimero-core/rules/context-is-not-app.md +35 -0
  30. package/skills/calimero-core/rules/crdt-types-only.md +55 -0
  31. package/skills/calimero-desktop/SKILL.md +24 -19
  32. package/skills/calimero-desktop/references/sso-integration.md +2 -2
  33. package/skills/calimero-desktop/rules/sso-fallback.md +3 -2
  34. package/skills/calimero-merobox/SKILL.md +255 -28
  35. package/skills/calimero-merobox/references/ci-integration.md +3 -2
  36. package/skills/calimero-merobox/references/workflow-files.md +7 -5
  37. package/skills/calimero-merobox/rules/docker-required.md +7 -6
  38. package/skills/calimero-meroctl/SKILL.md +68 -0
  39. package/skills/calimero-meroctl/references/commands.md +177 -0
  40. package/skills/calimero-meroctl/references/scripting.md +80 -0
  41. package/skills/calimero-meroctl/rules/call-view-flag.md +28 -0
  42. package/skills/calimero-meroctl/rules/register-node-once.md +34 -0
  43. package/skills/calimero-merod/SKILL.md +49 -0
  44. package/skills/calimero-merod/references/health-endpoints.md +90 -0
  45. package/skills/calimero-merod/references/init-flags.md +84 -0
  46. package/skills/calimero-merod/rules/init-before-run.md +40 -0
  47. package/skills/calimero-merod/rules/port-assignments.md +33 -0
  48. package/skills/calimero-node/SKILL.md +50 -39
  49. package/skills/calimero-node/references/context-lifecycle.md +34 -17
  50. package/skills/calimero-node/references/meroctl-commands.md +89 -99
  51. package/skills/calimero-node/rules/app-vs-context.md +4 -4
  52. package/skills/calimero-registry/SKILL.md +110 -31
  53. package/skills/calimero-registry/references/bundle-and-push.md +99 -34
  54. package/skills/calimero-registry/references/manifest-format.md +56 -35
  55. package/skills/calimero-registry/references/mero-sign.md +10 -9
  56. package/skills/calimero-registry/rules/key-security.md +3 -2
  57. package/skills/calimero-registry/rules/sign-before-pack.md +5 -5
  58. package/skills/calimero-rust-sdk/SKILL.md +154 -44
  59. package/skills/calimero-rust-sdk/references/blob-api.md +119 -0
  60. package/skills/calimero-rust-sdk/references/event-handlers.md +122 -0
  61. package/skills/calimero-rust-sdk/references/events.md +2 -1
  62. package/skills/calimero-rust-sdk/references/examples.md +81 -29
  63. package/skills/calimero-rust-sdk/references/migrations.md +123 -0
  64. package/skills/calimero-rust-sdk/references/nested-crdts.md +113 -0
  65. package/skills/calimero-rust-sdk/references/private-storage.md +76 -34
  66. package/skills/calimero-rust-sdk/references/state-collections.md +106 -21
  67. package/skills/calimero-rust-sdk/references/user-and-frozen-storage.md +169 -0
  68. package/skills/calimero-rust-sdk/rules/app-macro-placement.md +5 -2
  69. package/skills/calimero-rust-sdk/rules/no-std-collections.md +5 -2
  70. package/skills/calimero-rust-sdk/rules/state-derives.md +9 -10
  71. package/skills/calimero-rust-sdk/rules/wasm-constraints.md +12 -10
  72. package/skills/calimero-sdk-js/SKILL.md +34 -26
  73. package/skills/calimero-sdk-js/references/build-pipeline.md +6 -6
  74. package/skills/calimero-sdk-js/references/collections.md +11 -11
  75. package/skills/calimero-sdk-js/references/events.md +7 -3
  76. package/skills/calimero-sdk-js/rules/crdt-only-state.md +18 -18
  77. package/skills/calimero-sdk-js/rules/no-console-log.md +6 -6
  78. package/skills/calimero-sdk-js/rules/view-decorator.md +6 -4
@@ -2,7 +2,7 @@
2
2
 
3
3
  Running `calimero-abi-codegen -i abi.json -o src/generated --client-name KvStoreClient` produces:
4
4
 
5
- ```
5
+ ```text
6
6
  src/generated/
7
7
  ├── types.ts
8
8
  └── KvStoreClient.ts
@@ -36,7 +36,10 @@ import { CalimeroApp, Context } from '@calimero-network/calimero-client';
36
36
  import type { Entry } from './types';
37
37
 
38
38
  export class KvStoreClient {
39
- constructor(private app: CalimeroApp, private context: Context) {}
39
+ constructor(
40
+ private app: CalimeroApp,
41
+ private context: Context
42
+ ) {}
40
43
 
41
44
  async set(key: string, value: string): Promise<void> {
42
45
  await this.app.mutate(this.context, 'set', { key, value });
@@ -55,7 +58,12 @@ export class KvStoreClient {
55
58
  ## Using the generated client
56
59
 
57
60
  ```typescript
58
- import { CalimeroApp, Context, getJWTObject, getStorageAppEndpointKey } from '@calimero-network/calimero-client';
61
+ import {
62
+ CalimeroApp,
63
+ Context,
64
+ getJWTObject,
65
+ getStorageAppEndpointKey,
66
+ } from '@calimero-network/calimero-client';
59
67
  import { KvStoreClient } from './generated/KvStoreClient';
60
68
 
61
69
  const app = new CalimeroApp(getStorageAppEndpointKey(), getJWTObject()?.access_token);
@@ -65,7 +73,7 @@ const client = new KvStoreClient(app, context);
65
73
  // Fully typed — IDE autocomplete works
66
74
  await client.set('hello', 'world');
67
75
  const value = await client.get('hello'); // string | null
68
- const all = await client.entries(); // Entry[]
76
+ const all = await client.entries(); // Entry[]
69
77
  ```
70
78
 
71
79
  ## Regenerating after app changes
@@ -1,19 +1,24 @@
1
1
  # Rule: ABI manifest must have schema_version "wasm-abi/1"
2
2
 
3
- The codegen tool rejects any ABI file that doesn't have the exact string `"wasm-abi/1"` as its `schema_version`.
3
+ The codegen tool rejects any ABI file that doesn't have the exact string `"wasm-abi/1"` as its
4
+ `schema_version`.
4
5
 
5
6
  ## WRONG:
6
7
 
7
8
  ```json
8
9
  {
9
10
  "schema_version": "1",
10
- "types": {}, "methods": [], "events": []
11
+ "types": {},
12
+ "methods": [],
13
+ "events": []
11
14
  }
12
15
  ```
13
16
 
14
17
  ```json
15
18
  {
16
- "types": {}, "methods": [], "events": []
19
+ "types": {},
20
+ "methods": [],
21
+ "events": []
17
22
  }
18
23
  ```
19
24
 
@@ -22,7 +27,9 @@ The codegen tool rejects any ABI file that doesn't have the exact string `"wasm-
22
27
  ```json
23
28
  {
24
29
  "schema_version": "wasm-abi/1",
25
- "types": {}, "methods": [], "events": []
30
+ "types": {},
31
+ "methods": [],
32
+ "events": []
26
33
  }
27
34
  ```
28
35
 
@@ -20,9 +20,7 @@ The ABI validator rejects manifests where names clash — across methods, events
20
20
  "types": {
21
21
  "set": { "kind": "record", "fields": [] }
22
22
  },
23
- "methods": [
24
- { "name": "set", "params": [] }
25
- ]
23
+ "methods": [{ "name": "set", "params": [] }]
26
24
  }
27
25
  ```
28
26
 
@@ -43,9 +41,7 @@ Map keys **must** be `{ "kind": "string" }`.
43
41
  ```json
44
42
  {
45
43
  "types": {},
46
- "methods": [
47
- { "name": "get", "returns": { "$ref": "NonExistentType" } }
48
- ]
44
+ "methods": [{ "name": "get", "returns": { "$ref": "NonExistentType" } }]
49
45
  }
50
46
  ```
51
47
 
@@ -1,54 +1,135 @@
1
1
  # calimero-client-js — Agent Instructions
2
2
 
3
- You are helping a developer connect a **browser or Node.js frontend** to a Calimero node
4
- using `@calimero-network/calimero-client` or `@calimero-network/mero-js`.
3
+ You are helping a developer connect a **browser or Node.js frontend** to a Calimero node using
4
+ `@calimero-network/mero-react` (preferred) or `@calimero-network/calimero-client`.
5
5
 
6
- > **NOT this skill** if the developer is building the application logic that *runs on the
7
- > node* in TypeScript — that is `calimero-sdk-js` (`@calimero-network/calimero-sdk-js`).
8
- > This skill is for the *client* side: auth, RPC calls, and WebSocket subscriptions from
9
- > a browser or backend service.
6
+ > **NOT this skill** if the developer is building the application logic that _runs on the node_ in
7
+ > TypeScript — that is `calimero-sdk-js`. This skill is for the _client_ side: auth, RPC calls, and
8
+ > WebSocket subscriptions from a browser or React app.
10
9
 
11
10
  ## Package versions
12
11
 
13
- | Package | Version | Notes |
14
- | --- | --- | --- |
15
- | `@calimero-network/calimero-client` | latest | Stable client for browser/Node auth, RPC, WebSocket |
16
- | `@calimero-network/mero-js` | `>=2.0.0-beta.1` | v2 API all request fields are **camelCase** |
17
-
18
- **Which to use:** new projects should prefer `@calimero-network/mero-js` v2. If you are
19
- maintaining an existing codebase that uses `calimero-client`, check for snake_case field
20
- names before migrating — do not mix both packages in the same project.
12
+ | Package | Notes |
13
+ | ----------------------------------- | ----------------------------------------------------------------------------------------- |
14
+ | `@calimero-network/mero-react` | **Preferred for React apps.** Exports `MeroJs`, `useSubscription`, `MeroProvider`, hooks. |
15
+ | `@calimero-network/mero-js` | Core SDK. Zero deps. Used standalone in non-React contexts. |
16
+ | `@calimero-network/calimero-client` | Legacy client. Still works; new projects should prefer mero-react/mero-js. |
21
17
 
22
18
  ## Critical: mero-js v2 uses camelCase
23
19
 
24
- v2 changed all request field names from `snake_case` to `camelCase`.
20
+ All request field names changed from `snake_case` to `camelCase` in v2.
25
21
 
26
22
  ```typescript
27
- // WRONG (v1 / old):
23
+ // WRONG (v1):
28
24
  { context_id: '...', context_identity: '...' }
29
25
 
30
- // CORRECT (v2):
26
+ // CORRECT (v2 / mero-react):
31
27
  { contextId: '...', contextIdentity: '...' }
32
28
  ```
33
29
 
34
- This applies to `GenerateClientKeyRequest` and all other request types.
30
+ ## React app pattern (mero-react) recommended
35
31
 
36
- ## Install
32
+ ### Install
37
33
 
38
34
  ```bash
39
- pnpm add @calimero-network/calimero-client
40
- # or
41
- pnpm add @calimero-network/mero-js
35
+ pnpm add @calimero-network/mero-react
42
36
  ```
43
37
 
44
- ## Core workflow
38
+ ### Setup provider
39
+
40
+ ```tsx
41
+ import { MeroProvider } from '@calimero-network/mero-react';
42
+
43
+ function App() {
44
+ return (
45
+ <MeroProvider nodeUrl="http://localhost:2428">
46
+ <YourApp />
47
+ </MeroProvider>
48
+ );
49
+ }
50
+ ```
45
51
 
46
- 1. On startup: read SSO tokens from URL hash (if opened by Desktop), otherwise check `localStorage` for existing session, otherwise show login
47
- 2. Store tokens using the provided storage helpers (`setAppEndpointKey`, `setAccessToken`, etc.)
48
- 3. Call app methods via the `rpcClient` singleton using `rpcClient.execute()`
49
- 4. Subscribe to events via `WsSubscriptionsClient`
52
+ ### Call app methods
50
53
 
51
- ## Minimal working example
54
+ Generated clients (from abi-codegen) import `MeroJs` from `@calimero-network/mero-react`:
55
+
56
+ ```typescript
57
+ import { MeroJs } from '@calimero-network/mero-react';
58
+
59
+ export class KvClient {
60
+ constructor(
61
+ private mero: MeroJs,
62
+ private contextId: string,
63
+ private executorPublicKey: string
64
+ ) {}
65
+
66
+ async set(key: string, value: string): Promise<void> {
67
+ await this.mero.rpc.execute({
68
+ contextId: this.contextId,
69
+ method: 'set',
70
+ argsJson: { key, value },
71
+ executorPublicKey: this.executorPublicKey,
72
+ });
73
+ }
74
+
75
+ async get(key: string): Promise<string | null> {
76
+ const response = await this.mero.rpc.execute({
77
+ contextId: this.contextId,
78
+ method: 'get',
79
+ argsJson: { key },
80
+ executorPublicKey: this.executorPublicKey,
81
+ });
82
+ return response as string | null;
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### Subscribe to events (mero-react hook)
88
+
89
+ ```typescript
90
+ import { useSubscription } from '@calimero-network/mero-react';
91
+
92
+ // Subscribe to one or more contexts
93
+ useSubscription([contextId], (event: { contextId: string; data: unknown }) => {
94
+ // event.data may be:
95
+ // - { type: 'EventName', ...payload } for direct events
96
+ // - { events: [{ kind: string, data: unknown }] } for execution event batches
97
+ console.log('event:', event.data);
98
+ });
99
+
100
+ // Subscribe to multiple contexts (e.g. game + lobby simultaneously)
101
+ useSubscription([gameContextId, lobbyContextId], (event) => {
102
+ console.log('from context:', event.contextId);
103
+ });
104
+ ```
105
+
106
+ ### Parsing execution event payloads
107
+
108
+ Events from `app::emit!()` arrive batched in an `events` array. Each entry has `kind` (the variant
109
+ name) and `data` (the payload, possibly as a byte array):
110
+
111
+ ```typescript
112
+ function decodeEventData(data: unknown): unknown {
113
+ // If data is a number array, it's JSON-encoded bytes
114
+ if (Array.isArray(data) && data.every((n) => typeof n === 'number')) {
115
+ return JSON.parse(new TextDecoder().decode(new Uint8Array(data)));
116
+ }
117
+ return data;
118
+ }
119
+
120
+ // In the subscription callback:
121
+ useSubscription([contextId], (event) => {
122
+ const payload = event.data as any;
123
+ if (Array.isArray(payload?.events)) {
124
+ for (const e of payload.events) {
125
+ const decoded = decodeEventData(e.data);
126
+ console.log(e.kind, decoded); // e.g. "Inserted", { key: "...", value: "..." }
127
+ }
128
+ }
129
+ });
130
+ ```
131
+
132
+ ## Legacy calimero-client pattern
52
133
 
53
134
  ```typescript
54
135
  import {
@@ -78,7 +159,7 @@ const response = await rpcClient.execute<{ key: string }, string | null>({
78
159
  });
79
160
  console.log(response.result?.output);
80
161
 
81
- // 3. Subscribe to real-time events
162
+ // 3. Subscribe to events
82
163
  const ws = new WsSubscriptionsClient(getAppEndpointKey()!, '/ws');
83
164
  await ws.connect();
84
165
  ws.subscribe([getContextId()!]);
@@ -91,7 +172,21 @@ ws.addCallback((event) => {
91
172
  });
92
173
  ```
93
174
 
175
+ ## Core workflow
176
+
177
+ 1. On startup: read SSO tokens from URL hash (if opened by Desktop), otherwise check `localStorage`,
178
+ otherwise show login
179
+ 2. Store tokens using storage helpers or the `MeroProvider` (handles this automatically)
180
+ 3. Call app methods via the generated typed client or `mero.rpc.execute()`
181
+ 4. Subscribe to events via `useSubscription` (React) or `WsSubscriptionsClient`
182
+
183
+ ## Related skills
184
+
185
+ - **`calimero-core`** — JSON-RPC protocol spec, WebSocket event schemas, context/app/identity model
186
+ - **`calimero-desktop`** — SSO token passing from Calimero Desktop (URL hash flow)
187
+ - **`calimero-node`** — node setup if the developer is also running the node
188
+
94
189
  ## References
95
190
 
96
- See `references/` for auth flow, RPC calls, WebSocket events, and SSO.
97
- See `rules/` for camelCase API and token refresh requirements.
191
+ See `references/` for auth flow, RPC calls, WebSocket events, and SSO. See `rules/` for camelCase
192
+ API and token refresh requirements.
@@ -19,7 +19,7 @@ import {
19
19
  getContextId,
20
20
  setExecutorPublicKey,
21
21
  getExecutorPublicKey,
22
- setContextAndIdentityFromJWT, // extracts + stores contextId + executorPublicKey from JWT
22
+ setContextAndIdentityFromJWT, // extracts + stores contextId + executorPublicKey from JWT
23
23
  // App ID
24
24
  setApplicationId,
25
25
  getApplicationId,
@@ -27,9 +27,9 @@ import {
27
27
  setAuthEndpointURL,
28
28
  getAuthEndpointURL,
29
29
  // Decoded JWT payload
30
- getJWTObject, // returns { context_id, context_identity, exp, permissions, ... }
30
+ getJWTObject, // returns { context_id, context_identity, exp, permissions, ... }
31
31
  // Full auth config (throws if required fields are missing)
32
- getAuthConfig, // returns { appEndpointKey, contextId, executorPublicKey, jwtToken }
32
+ getAuthConfig, // returns { appEndpointKey, contextId, executorPublicKey, jwtToken }
33
33
  // Logout (clears all tokens + reloads)
34
34
  clientLogout,
35
35
  } from '@calimero-network/calimero-client';
@@ -44,10 +44,10 @@ When the app is opened by Desktop, tokens arrive in the URL hash. Store them:
44
44
  ```typescript
45
45
  function initFromDesktopSSO(): boolean {
46
46
  const hash = new URLSearchParams(window.location.hash.slice(1));
47
- const accessToken = hash.get('access_token');
47
+ const accessToken = hash.get('access_token');
48
48
  const refreshToken = hash.get('refresh_token');
49
- const nodeUrl = hash.get('node_url');
50
- const appId = hash.get('application_id');
49
+ const nodeUrl = hash.get('node_url');
50
+ const appId = hash.get('application_id');
51
51
 
52
52
  if (!accessToken || !nodeUrl) return false;
53
53
 
@@ -72,7 +72,12 @@ function initFromDesktopSSO(): boolean {
72
72
  ## Manual login (no Desktop)
73
73
 
74
74
  ```typescript
75
- import { setAppEndpointKey, setAccessToken, setRefreshToken, setContextAndIdentityFromJWT } from '@calimero-network/calimero-client';
75
+ import {
76
+ setAppEndpointKey,
77
+ setAccessToken,
78
+ setRefreshToken,
79
+ setContextAndIdentityFromJWT,
80
+ } from '@calimero-network/calimero-client';
76
81
 
77
82
  async function login(nodeUrl: string, accessToken: string, refreshToken: string) {
78
83
  setAppEndpointKey(nodeUrl);
@@ -126,8 +131,11 @@ clientLogout();
126
131
 
127
132
  ```typescript
128
133
  import {
129
- setAppEndpointKey, setAccessToken, setRefreshToken,
130
- setApplicationId, setContextAndIdentityFromJWT,
134
+ setAppEndpointKey,
135
+ setAccessToken,
136
+ setRefreshToken,
137
+ setApplicationId,
138
+ setContextAndIdentityFromJWT,
131
139
  getAuthConfig,
132
140
  } from '@calimero-network/calimero-client';
133
141
 
@@ -135,7 +143,7 @@ async function bootstrap() {
135
143
  // Try SSO from Desktop hash
136
144
  const hash = new URLSearchParams(window.location.hash.slice(1));
137
145
  const accessToken = hash.get('access_token');
138
- const nodeUrl = hash.get('node_url');
146
+ const nodeUrl = hash.get('node_url');
139
147
 
140
148
  if (accessToken && nodeUrl) {
141
149
  setAppEndpointKey(nodeUrl);
@@ -4,15 +4,11 @@ Calling application methods on a Calimero node.
4
4
 
5
5
  ## The `rpcClient` singleton
6
6
 
7
- `@calimero-network/calimero-client` exports a pre-configured `rpcClient` singleton.
8
- Import it directly — do not construct `JsonRpcClient` manually.
7
+ `@calimero-network/calimero-client` exports a pre-configured `rpcClient` singleton. Import it
8
+ directly — do not construct `JsonRpcClient` manually.
9
9
 
10
10
  ```typescript
11
- import {
12
- rpcClient,
13
- getContextId,
14
- getExecutorPublicKey,
15
- } from '@calimero-network/calimero-client';
11
+ import { rpcClient, getContextId, getExecutorPublicKey } from '@calimero-network/calimero-client';
16
12
  ```
17
13
 
18
14
  ---
@@ -23,7 +19,9 @@ import {
23
19
  const response = await rpcClient.execute<ArgsType, OutputType>({
24
20
  contextId: getContextId()!,
25
21
  method: 'methodName',
26
- argsJson: { /* your args */ },
22
+ argsJson: {
23
+ /* your args */
24
+ },
27
25
  executorPublicKey: getExecutorPublicKey()!,
28
26
  });
29
27
 
@@ -96,20 +94,20 @@ if (!response.error) {
96
94
 
97
95
  ## Error names
98
96
 
99
- | name | meaning |
100
- |---|---|
101
- | `FunctionCallError` | App method returned an error |
102
- | `RpcExecutionError` | Node couldn't execute the method |
97
+ | name | meaning |
98
+ | --------------------- | -------------------------------------------------- |
99
+ | `FunctionCallError` | App method returned an error |
100
+ | `RpcExecutionError` | Node couldn't execute the method |
103
101
  | `InvalidRequestError` | Malformed request (wrong context-id, missing args) |
104
- | `AuthenticationError` | JWT expired, revoked, or missing |
105
- | `UnknownServerError` | Unexpected server error |
102
+ | `AuthenticationError` | JWT expired, revoked, or missing |
103
+ | `UnknownServerError` | Unexpected server error |
106
104
 
107
105
  ---
108
106
 
109
107
  ## Error handling with 401
110
108
 
111
- The HTTP client inside `rpcClient` automatically refreshes tokens on `401 token_expired`.
112
- For `token_revoked` or `invalid_token` you need to re-authenticate:
109
+ The HTTP client inside `rpcClient` automatically refreshes tokens on `401 token_expired`. For
110
+ `token_revoked` or `invalid_token` you need to re-authenticate:
113
111
 
114
112
  ```typescript
115
113
  const response = await rpcClient.execute({ ... });
@@ -133,11 +131,7 @@ if (response.error) {
133
131
  ## Complete example: typed wrapper
134
132
 
135
133
  ```typescript
136
- import {
137
- rpcClient,
138
- getContextId,
139
- getExecutorPublicKey,
140
- } from '@calimero-network/calimero-client';
134
+ import { rpcClient, getContextId, getExecutorPublicKey } from '@calimero-network/calimero-client';
141
135
 
142
136
  async function setItem(key: string, value: string): Promise<void> {
143
137
  const response = await rpcClient.execute<{ key: string; value: string }, void>({
@@ -1,15 +1,15 @@
1
1
  # SSO — Calimero Desktop Integration
2
2
 
3
- When a user opens your app from Calimero Desktop, auth tokens are passed via the URL hash.
4
- Reading them lets users skip the manual login flow entirely.
3
+ When a user opens your app from Calimero Desktop, auth tokens are passed via the URL hash. Reading
4
+ them lets users skip the manual login flow entirely.
5
5
 
6
6
  ## Hash parameters
7
7
 
8
- | Parameter | Description |
9
- | --- | --- |
10
- | `access_token` | JWT for authenticated node calls |
11
- | `refresh_token` | Token to obtain a new access token |
12
- | `node_url` | URL of the local node to connect to |
8
+ | Parameter | Description |
9
+ | ---------------- | ------------------------------------------ |
10
+ | `access_token` | JWT for authenticated node calls |
11
+ | `refresh_token` | Token to obtain a new access token |
12
+ | `node_url` | URL of the local node to connect to |
13
13
  | `application_id` | The installed application's ID on the node |
14
14
 
15
15
  ## Reading from hash
@@ -68,5 +68,5 @@ async function initApp() {
68
68
 
69
69
  ## Important
70
70
 
71
- Always fall back to manual login if the hash params are absent — the app must work
72
- when opened directly in a browser, not only from Desktop.
71
+ Always fall back to manual login if the hash params are absent — the app must work when opened
72
+ directly in a browser, not only from Desktop.