@dxos/edge-client 0.9.1-main.c7dcc2e112 → 0.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/edge-client",
3
- "version": "0.9.1-main.c7dcc2e112",
3
+ "version": "0.10.0",
4
4
  "description": "EDGE Client",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -46,29 +46,29 @@
46
46
  "README.md"
47
47
  ],
48
48
  "dependencies": {
49
- "@effect/platform": "0.96.1",
49
+ "@effect/platform": "0.96.2",
50
50
  "@opentelemetry/api": "^1.9.1",
51
51
  "isomorphic-ws": "^5.0.0",
52
52
  "ws": "^8.17.1",
53
- "@dxos/context": "0.9.1-main.c7dcc2e112",
54
- "@dxos/credentials": "0.9.1-main.c7dcc2e112",
55
- "@dxos/async": "0.9.1-main.c7dcc2e112",
56
- "@dxos/errors": "0.9.1-main.c7dcc2e112",
57
- "@dxos/effect": "0.9.1-main.c7dcc2e112",
58
- "@dxos/invariant": "0.9.1-main.c7dcc2e112",
59
- "@dxos/keyring": "0.9.1-main.c7dcc2e112",
60
- "@dxos/keys": "0.9.1-main.c7dcc2e112",
61
- "@dxos/node-std": "0.9.1-main.c7dcc2e112",
62
- "@dxos/log": "0.9.1-main.c7dcc2e112",
63
- "@dxos/protocols": "0.9.1-main.c7dcc2e112",
64
- "@dxos/crypto": "0.9.1-main.c7dcc2e112",
65
- "@dxos/util": "0.9.1-main.c7dcc2e112"
53
+ "@dxos/async": "0.10.0",
54
+ "@dxos/effect": "0.10.0",
55
+ "@dxos/context": "0.10.0",
56
+ "@dxos/errors": "0.10.0",
57
+ "@dxos/crypto": "0.10.0",
58
+ "@dxos/invariant": "0.10.0",
59
+ "@dxos/keyring": "0.10.0",
60
+ "@dxos/keys": "0.10.0",
61
+ "@dxos/node-std": "0.10.0",
62
+ "@dxos/protocols": "0.10.0",
63
+ "@dxos/log": "0.10.0",
64
+ "@dxos/util": "0.10.0",
65
+ "@dxos/credentials": "0.10.0"
66
66
  },
67
67
  "devDependencies": {
68
- "@dxos/test-utils": "0.9.1-main.c7dcc2e112"
68
+ "@dxos/test-utils": "0.10.0"
69
69
  },
70
70
  "peerDependencies": {
71
- "effect": "3.21.3"
71
+ "effect": "3.21.4"
72
72
  },
73
73
  "publishConfig": {
74
74
  "access": "public"
package/src/auth.ts CHANGED
@@ -2,11 +2,11 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { createCredential, signPresentation } from '@dxos/credentials';
5
+ import { createCredential, createDidFromIdentityKey, signPresentation } from '@dxos/credentials';
6
6
  import { type Signer } from '@dxos/crypto';
7
7
  import { invariant } from '@dxos/invariant';
8
8
  import { Keyring } from '@dxos/keyring';
9
- import { PublicKey } from '@dxos/keys';
9
+ import { IdentityDid, PublicKey } from '@dxos/keys';
10
10
  import { type Chain, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
11
11
 
12
12
  import type { EdgeIdentity } from './edge-identity';
@@ -16,7 +16,7 @@ import type { EdgeIdentity } from './edge-identity';
16
16
  */
17
17
  export const createDeviceEdgeIdentity = async (signer: Signer, key: PublicKey): Promise<EdgeIdentity> => {
18
18
  return {
19
- identityKey: key.toHex(),
19
+ identityDid: await createDidFromIdentityKey(key),
20
20
  peerKey: key.toHex(),
21
21
  presentCredentials: async ({ challenge }) => {
22
22
  return signPresentation({
@@ -68,7 +68,7 @@ export const createChainEdgeIdentity = async (
68
68
  ];
69
69
 
70
70
  return {
71
- identityKey: identityKey.toHex(),
71
+ identityDid: await createDidFromIdentityKey(identityKey),
72
72
  peerKey: peerKey.toHex(),
73
73
  presentCredentials: async ({ challenge }) => {
74
74
  // TODO: make chain required after device invitation flow update release
@@ -126,10 +126,10 @@ export const createTestHaloEdgeIdentity = async (
126
126
  };
127
127
 
128
128
  export const createStubEdgeIdentity = (): EdgeIdentity => {
129
- const identityKey = PublicKey.random();
130
129
  const deviceKey = PublicKey.random();
131
130
  return {
132
- identityKey: identityKey.toHex(),
131
+ // Random placeholder DID — the stub never authenticates or connects; a real identity replaces it.
132
+ identityDid: IdentityDid.random(),
133
133
  peerKey: deviceKey.toHex(),
134
134
  presentCredentials: async () => {
135
135
  throw new Error('Stub identity does not support authentication.');
@@ -71,7 +71,7 @@ export abstract class BaseHttpClient {
71
71
  }
72
72
 
73
73
  setIdentity(identity: EdgeIdentity): void {
74
- if (this._edgeIdentity?.identityKey !== identity.identityKey || this._edgeIdentity?.peerKey !== identity.peerKey) {
74
+ if (this._edgeIdentity?.identityDid !== identity.identityDid || this._edgeIdentity?.peerKey !== identity.peerKey) {
75
75
  this._edgeIdentity = identity;
76
76
  this._authHeader = undefined;
77
77
  }
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Context from 'effect/Context';
6
+ import * as Schema from 'effect/Schema';
7
+
8
+ import { type EdgeHttpClient } from './edge-http-client';
9
+
10
+ /** Request body for EDGE `/ai/browser-rendering/markdown` (ai-service Browser Run markdown quick action). */
11
+ export const MarkdownRequest = Schema.Struct({
12
+ url: Schema.optional(Schema.String),
13
+ html: Schema.optional(Schema.String),
14
+ gotoOptions: Schema.optional(
15
+ Schema.Struct({
16
+ waitUntil: Schema.optional(Schema.Literal('load', 'domcontentloaded', 'networkidle0', 'networkidle2')),
17
+ timeout: Schema.optional(Schema.Number),
18
+ }),
19
+ ),
20
+ rejectRequestPattern: Schema.optional(Schema.Array(Schema.String)),
21
+ userAgent: Schema.optional(Schema.String),
22
+ waitForSelector: Schema.optional(Schema.String),
23
+ });
24
+
25
+ export type MarkdownRequest = Schema.Schema.Type<typeof MarkdownRequest>;
26
+
27
+ /** JSON body returned by Cloudflare Browser Run markdown quick action. */
28
+ export const MarkdownResponse = Schema.Struct({
29
+ success: Schema.Boolean,
30
+ result: Schema.String,
31
+ });
32
+
33
+ export type MarkdownResponse = Schema.Schema.Type<typeof MarkdownResponse>;
34
+
35
+ /** Authenticated EDGE HTTP client for operation handlers (e.g. browser markdown fetch). */
36
+ export class EdgeHttpClientService extends Context.Tag('@dxos/edge-client/EdgeHttpClientService')<
37
+ EdgeHttpClientService,
38
+ EdgeHttpClient
39
+ >() {}
@@ -158,7 +158,7 @@ describe('EdgeClient', () => {
158
158
 
159
159
  const textMessage = (message: string, source?: EdgeIdentity) =>
160
160
  protocol.createMessage(TextMessageSchema, {
161
- source: source && { peerKey: source.peerKey, identityKey: source.identityKey },
161
+ source: source && { peerKey: source.peerKey, identityDid: source.identityDid },
162
162
  payload: { message },
163
163
  });
164
164
 
@@ -43,7 +43,8 @@ export type MessengerConfig = {
43
43
  export interface EdgeConnection extends Required<Lifecycle> {
44
44
  statusChanged: Event<EdgeStatus>;
45
45
  get info(): any;
46
- get identityKey(): string;
46
+ /** Identity DID (`did:halo:…`) of the connected identity. */
47
+ get identityDid(): string;
47
48
  get peerKey(): string;
48
49
  get isOpen(): boolean;
49
50
  get status(): EdgeStatus;
@@ -88,7 +89,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
88
89
  return {
89
90
  open: this.isOpen,
90
91
  status: this.status,
91
- identity: this._identity.identityKey,
92
+ identity: this._identity.identityDid,
92
93
  device: this._identity.peerKey,
93
94
  };
94
95
  }
@@ -108,8 +109,8 @@ export class EdgeClient extends Resource implements EdgeConnection {
108
109
  };
109
110
  }
110
111
 
111
- get identityKey() {
112
- return this._identity.identityKey;
112
+ get identityDid() {
113
+ return this._identity.identityDid;
113
114
  }
114
115
 
115
116
  get peerKey() {
@@ -117,7 +118,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
117
118
  }
118
119
 
119
120
  setIdentity(identity: EdgeIdentity) {
120
- if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
121
+ if (identity.identityDid !== this._identity.identityDid || identity.peerKey !== this._identity.peerKey) {
121
122
  log('Edge identity changed', { identity, oldIdentity: this._identity });
122
123
  this._identity = identity;
123
124
  this._closeCurrentConnection(new EdgeIdentityChangedError());
@@ -139,9 +140,10 @@ export class EdgeClient extends Resource implements EdgeConnection {
139
140
  throw new EdgeConnectionClosedError();
140
141
  }
141
142
 
143
+ // DX-1059: sources are DID-only; validate against identityDid.
142
144
  if (
143
145
  message.source &&
144
- (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)
146
+ (message.source.peerKey !== this._identity.peerKey || message.source.identityDid !== this.identityDid)
145
147
  ) {
146
148
  throw new EdgeIdentityChangedError();
147
149
  }
@@ -219,7 +221,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
219
221
  }
220
222
 
221
223
  const identity = this._identity;
222
- const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
224
+ const path = `/ws/${identity.identityDid}/${identity.peerKey}`;
223
225
  const protocolHeader = this._config.disableAuth ? undefined : await this._createAuthHeader(path);
224
226
  if (this._identity !== identity) {
225
227
  log('identity changed during auth header request');
@@ -11,7 +11,7 @@ import * as Function from 'effect/Function';
11
11
  import { type Context } from '@dxos/context';
12
12
  import { EffectEx } from '@dxos/effect';
13
13
  import { invariant } from '@dxos/invariant';
14
- import { type PublicKey, type SpaceId } from '@dxos/keys';
14
+ import { type SpaceId } from '@dxos/keys';
15
15
  import { log } from '@dxos/log';
16
16
  import {
17
17
  type CompleteOAuthRegistrationRequest,
@@ -117,10 +117,10 @@ export class EdgeHttpClient extends BaseHttpClient {
117
117
 
118
118
  public getAgentStatus(
119
119
  ctx: Context,
120
- request: { ownerIdentityKey: PublicKey },
120
+ request: { ownerIdentityDid: string },
121
121
  args?: EdgeHttpCallArgs,
122
122
  ): Promise<GetAgentStatusResponseBody> {
123
- return this._call(ctx, new URL(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, this.baseUrl), {
123
+ return this._call(ctx, new URL(`/users/${request.ownerIdentityDid}/agent/status`, this.baseUrl), {
124
124
  ...args,
125
125
  method: 'GET',
126
126
  });
@@ -271,7 +271,10 @@ export class EdgeHttpClient extends BaseHttpClient {
271
271
  const formData = new FormData();
272
272
  formData.append('name', body.name ?? '');
273
273
  formData.append('version', body.version);
274
- formData.append('ownerPublicKey', body.ownerPublicKey);
274
+ // The function owner is the authenticated identity (edge requires ownerUri === presenter DID).
275
+ // Prefer the connected identity's DID; otherwise use the DID supplied on the request body.
276
+ const ownerUri = this._edgeIdentity?.identityDid ?? body.ownerUri;
277
+ formData.append('ownerUri', ownerUri);
275
278
  formData.append('entryPoint', body.entryPoint);
276
279
  body.runtime && formData.append('runtime', body.runtime);
277
280
  for (const [filename, content] of Object.entries(body.assets)) {
@@ -8,7 +8,11 @@ import { type Presentation } from '@dxos/protocols/proto/dxos/halo/credentials';
8
8
 
9
9
  export interface EdgeIdentity {
10
10
  peerKey: string;
11
- identityKey: string;
11
+ /**
12
+ * Identity DID (`did:halo:…`) — the public identity segment of the edge WebSocket path.
13
+ * The router keys connections by the DID.
14
+ */
15
+ identityDid: string;
12
16
  /**
13
17
  * Returns credential presentation issued by the identity key.
14
18
  * Presentation must have the provided challenge.
@@ -60,7 +60,7 @@ export class EdgeWsConnection extends Resource {
60
60
  public get info() {
61
61
  return {
62
62
  open: this.isOpen,
63
- identity: this._identity.identityKey,
63
+ identity: this._identity.identityDid,
64
64
  device: this._identity.peerKey,
65
65
  };
66
66
  }
@@ -35,7 +35,7 @@ describe('WebSocketMuxerTest', () => {
35
35
 
36
36
  const textMessage = (message: string, source?: EdgeIdentity) =>
37
37
  protocol.createMessage(TextMessageSchema, {
38
- source: source && { peerKey: source.peerKey, identityKey: source.identityKey },
38
+ source: source && { peerKey: source.peerKey, identityDid: source.identityDid },
39
39
  serviceId: 'test-service',
40
40
  payload: { message },
41
41
  });
@@ -6,6 +6,7 @@ import { type Context } from '@dxos/context';
6
6
  import {
7
7
  type CheckEmailExistsResponse,
8
8
  type GetAccountResponse,
9
+ type GetProfileUsageResponse,
9
10
  type IssueInvitationResponse,
10
11
  type ListAccountInvitationsResponse,
11
12
  type LoginRequest,
@@ -14,7 +15,6 @@ import {
14
15
  type RedeemInvitationCodeResponse,
15
16
  type RequestAccessRequest,
16
17
  type RequestAccessResponse,
17
- type GetProfileUsageResponse,
18
18
  type ResendVerificationEmailResponse,
19
19
  type ValidateInvitationCodeResponse,
20
20
  } from '@dxos/protocols';
@@ -106,7 +106,7 @@ const createResponseSender = (connection: () => WebSocketMuxer) => {
106
106
  void connection().send(
107
107
  buf.create(MessageSchema, {
108
108
  source: {
109
- identityKey: recipient.identityKey,
109
+ identityDid: recipient.identityDid,
110
110
  peerKey: recipient.peerKey,
111
111
  },
112
112
  serviceId: request.serviceId!,