@dxos/halo 0.0.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/API_AUDIT.md +396 -0
- package/CONSUMER_MIGRATION.md +343 -0
- package/LICENSE +105 -0
- package/MIGRATION.md +254 -0
- package/MIGRATION_PLAN.md +217 -0
- package/README.md +25 -0
- package/SPEC.mdl +137 -0
- package/dist/lib/neutral/index.mjs +186 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/types/src/Identity.d.ts +166 -0
- package/dist/types/src/Identity.d.ts.map +1 -0
- package/dist/types/src/Invitation.d.ts +87 -0
- package/dist/types/src/Invitation.d.ts.map +1 -0
- package/dist/types/src/Space.d.ts +158 -0
- package/dist/types/src/Space.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +228 -0
- package/dist/types/src/errors.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/docs/halo.drawio.svg +119 -0
- package/moon.yml +11 -0
- package/package.json +31 -0
- package/src/Identity.ts +195 -0
- package/src/Invitation.ts +95 -0
- package/src/Space.ts +192 -0
- package/src/errors.ts +41 -0
- package/src/index.ts +9 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# Consumer Migration — `@dxos/client` HALO → `@dxos/halo` services
|
|
2
|
+
|
|
3
|
+
How to move Composer (`packages/apps/composer-app`) and the plugins
|
|
4
|
+
(`packages/plugins/*`) off direct `@dxos/client` HALO access and onto the
|
|
5
|
+
`@dxos/halo` Effect services (backed by `@dxos/halo-adapter-client`).
|
|
6
|
+
|
|
7
|
+
Companion to [API_AUDIT.md](./API_AUDIT.md) (what the consumers use today) and
|
|
8
|
+
[MIGRATION.md](./MIGRATION.md) (the HALO → Keyhive backend rewrite). This
|
|
9
|
+
document is the practical cookbook: the decisive verdict on coverage, then
|
|
10
|
+
before→after patterns for the cases the services already handle.
|
|
11
|
+
|
|
12
|
+
## Verdict
|
|
13
|
+
|
|
14
|
+
**The new API cannot yet replace `@dxos/client` everywhere in Composer and the
|
|
15
|
+
plugins.** The two services (`Identity`, `Space`) — plus the serviceless
|
|
16
|
+
`Invitation` flow types/verbs — cover the imperative HALO surface:
|
|
17
|
+
identity/device lifecycle, space management and membership, and the invitation
|
|
18
|
+
state machine (initiation and querying live on `Identity`/`Space`). The
|
|
19
|
+
`layerClient(client)`
|
|
20
|
+
composition root drops in wherever a plugin already holds a `Client`. That is
|
|
21
|
+
enough to migrate imperative call sites (operation handlers, CLI commands,
|
|
22
|
+
managers, import scripts).
|
|
23
|
+
|
|
24
|
+
It is **not** enough to migrate the codebase wholesale. Four gaps remain, each
|
|
25
|
+
with an agreed disposition:
|
|
26
|
+
|
|
27
|
+
1. **React bindings — `@dxos/halo-react`.** There are ~368 uses of
|
|
28
|
+
`useIdentity` / `useDevices` / `useCredentials` / `useSpaces` / `useSpace` /
|
|
29
|
+
`useMembers` / `useSpaceInvitations` across 163 files — the bulk of the
|
|
30
|
+
consumer surface. The new [`@dxos/halo-react`](../halo-react) hook library
|
|
31
|
+
provides drop-in equivalents backed by the HALO services (each reactive read
|
|
32
|
+
is a current-value `Stream` surfaced through `@effect-atom` atoms and
|
|
33
|
+
`useAtomValue`). Components migrate hook-by-hook
|
|
34
|
+
by swapping the import and wrapping the tree in `HaloProvider` instead of
|
|
35
|
+
`ClientProvider`; see [Migrating React hooks](#migrating-react-hooks). Hooks
|
|
36
|
+
with no service verb yet (`useCredentials`) stay on `@dxos/react-client`.
|
|
37
|
+
2. **ECHO database access — a separate track, by design.** `Space.Info` is a
|
|
38
|
+
plain snapshot, not a live proxy — it has no `.db`, `.crud`, `.properties`,
|
|
39
|
+
or `.internal`. The heavy `space.db.*` / `space.internal.*` usage is ECHO,
|
|
40
|
+
not HALO, and belongs on the `@dxos/echo` `Database` service keyed by
|
|
41
|
+
`SpaceId`. This is not folded into HALO. See API_AUDIT.md §3.6.
|
|
42
|
+
3. **Deferred verbs — planned, not yet defined.** Credentials
|
|
43
|
+
(`halo.queryCredentials` / `writeCredentials`), recovery-credential
|
|
44
|
+
_creation_ (`createRecoveryCredential` / `requestRecoveryChallenge`), EDGE
|
|
45
|
+
`createEdgeIdentity` / attestation, and device _update_ will be added as
|
|
46
|
+
`Identity`-service verbs in a follow-up. Consumers of those stay on the
|
|
47
|
+
client until then.
|
|
48
|
+
4. **Space create/lifecycle gaps — mostly closed.** `Space.create` now accepts
|
|
49
|
+
`{ name?, tags?, membershipPolicy? }`, and EDGE replication is toggled with
|
|
50
|
+
`Space.setEdgeReplication(id, setting)`. `migrate` is intentionally left out.
|
|
51
|
+
`State` remains the consumer-relevant subset (`inactive` / `closed` /
|
|
52
|
+
`ready`), not the full `SpaceState` enum.
|
|
53
|
+
|
|
54
|
+
So: migrate imperative HALO call sites now; leave React components and ECHO
|
|
55
|
+
access on `@dxos/client` until the binding rewrite and the ECHO `Database`
|
|
56
|
+
service land, and the deferred verbs (§3) until they are defined. The rest of
|
|
57
|
+
this doc covers the cases that _can_ move.
|
|
58
|
+
|
|
59
|
+
## Composition root
|
|
60
|
+
|
|
61
|
+
Every plugin already obtains its `Client` from the
|
|
62
|
+
`ClientCapabilities.Client` capability provided by `plugin-client` — a single
|
|
63
|
+
injection point. Build the HALO layer once from that client and provide it to
|
|
64
|
+
any effect:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { layerClient } from '@dxos/halo-adapter-client';
|
|
68
|
+
import { Identity, Space } from '@dxos/halo';
|
|
69
|
+
|
|
70
|
+
const halo = layerClient(client); // Layer<Identity.Service | Space.Service>
|
|
71
|
+
|
|
72
|
+
const program = Effect.gen(function* () {
|
|
73
|
+
// Reactive reads are current-value streams; take the head for a one-shot snapshot.
|
|
74
|
+
const identity = yield* Stream.runHead(Identity.identity);
|
|
75
|
+
const spaces = yield* Stream.runHead(Space.spaces);
|
|
76
|
+
// ...
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await Effect.runPromise(program.pipe(Effect.provide(halo)));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`layerClient` is the seam that replaces direct `@dxos/client` access for HALO
|
|
83
|
+
concerns. The backend behind it (legacy client, EDGE shim, or Keyhive) can swap
|
|
84
|
+
without touching consumers.
|
|
85
|
+
|
|
86
|
+
## Migrating React hooks
|
|
87
|
+
|
|
88
|
+
Most consumer usage is React hooks, not imperative calls. The
|
|
89
|
+
[`@dxos/halo-react`](../halo-react) package mirrors `@dxos/react-client`'s
|
|
90
|
+
HALO/space hooks, backed by the services. Migration is mechanical: swap the
|
|
91
|
+
provider, then swap imports hook-by-hook.
|
|
92
|
+
|
|
93
|
+
**1. Swap the provider.** `@dxos/halo-react` reads the services off a React
|
|
94
|
+
context holding an Effect `Context.Context<Identity | Space | Invitation>`.
|
|
95
|
+
Build that context once (from the client adapter, or any backing) and wrap the
|
|
96
|
+
tree:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { Context } from 'effect';
|
|
100
|
+
import { Identity, Space } from '@dxos/halo';
|
|
101
|
+
import { makeIdentityService, makeSpaceService } from '@dxos/halo-adapter-client';
|
|
102
|
+
import { HaloProvider } from '@dxos/halo-react';
|
|
103
|
+
|
|
104
|
+
const services = Context.empty().pipe(
|
|
105
|
+
Context.add(Identity.Service, makeIdentityService(client)),
|
|
106
|
+
Context.add(Space.Service, makeSpaceService(client)),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Replaces <ClientProvider> for HALO concerns.
|
|
110
|
+
<HaloProvider services={services}>{children}</HaloProvider>;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
In a plugin this context is built once at the `plugin-client` composition root
|
|
114
|
+
(where the `Client` capability lives) and provided app-wide.
|
|
115
|
+
|
|
116
|
+
**2. Swap the hooks.** Same names, same call shape; the returned values are the
|
|
117
|
+
HALO snapshot types (`Identity.Info`, `Space.Info`, `Space.Member`,
|
|
118
|
+
`Invitation.Flow`) instead of the client proxy types.
|
|
119
|
+
|
|
120
|
+
| `@dxos/react-client` hook | `@dxos/halo-react` hook | Return type | Notes |
|
|
121
|
+
| --------------------------------- | --------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------- |
|
|
122
|
+
| `useIdentity(): Identity \| null` | `useIdentity(): Identity.Info \| undefined` | `{ did, displayName? }` | `null` → `undefined`; `did` replaces `identityKey`/`spaceKey` |
|
|
123
|
+
| `useDevices(): Device[]` | `useDevices(): readonly Identity.DeviceInfo[]` | `{ key, kind?, label?, current }` | — |
|
|
124
|
+
| `useSpaces({ all? }): Space[]` | `useSpaces({ all? }): readonly Space.Info[]` | `{ id, name?, state }` | same `all` option and `ready`-only default |
|
|
125
|
+
| `useSpace(id \| key): Space` | `useSpace(id?: SpaceId): Space.Info \| undefined` | snapshot | `SpaceId` only — no `PublicKey` |
|
|
126
|
+
| `useMembers(key): SpaceMember[]` | `useMembers(id?: SpaceId): readonly Space.Member[]` | `{ did?, role, online }` | takes a `SpaceId`, not a key; `role` is `Space.Access` |
|
|
127
|
+
| `useSpaceInvitations(id \| key)` | `useSpaceInvitations(id?: SpaceId): readonly Invitation.Flow[]` | `Invitation.Flow[]` | drive each flow via the `Invitation` verbs |
|
|
128
|
+
| `useHaloInvitations()` | `useHaloInvitations(): readonly Invitation.Flow[]` | `Invitation.Flow[]` | — |
|
|
129
|
+
| `useCredentials()` | _not yet_ | — | no credential verb yet (§3) — stays on `@dxos/react-client` |
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// Before
|
|
133
|
+
import { useIdentity } from '@dxos/react-client/halo';
|
|
134
|
+
import { useSpaces, useMembers } from '@dxos/react-client/echo';
|
|
135
|
+
|
|
136
|
+
// After
|
|
137
|
+
import { useIdentity, useSpaces, useMembers } from '@dxos/halo-react';
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**3. ECHO stays put.** `useQuery` and other `@dxos/react-client/echo` database
|
|
141
|
+
hooks are ECHO, not HALO — they do not move here (§2).
|
|
142
|
+
|
|
143
|
+
For imperative call sites (operation handlers, CLI commands), use the service
|
|
144
|
+
verbs directly rather than hooks — those patterns follow.
|
|
145
|
+
|
|
146
|
+
## Patterns
|
|
147
|
+
|
|
148
|
+
Each pattern shows the current `@dxos/client` call and its `@dxos/halo`
|
|
149
|
+
equivalent. All effects require the corresponding service in `R`; provide
|
|
150
|
+
`layerClient(client)`.
|
|
151
|
+
|
|
152
|
+
### Identity — read / gate
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// Before
|
|
156
|
+
const identity = client.halo.identity.get();
|
|
157
|
+
if (!identity) return;
|
|
158
|
+
const did = identity.did;
|
|
159
|
+
|
|
160
|
+
// After — reads are current-value streams; take the head for a one-shot read
|
|
161
|
+
const maybe = Option.flatten(yield * Stream.runHead(Identity.identity)); // Option<Identity.Info>
|
|
162
|
+
if (Option.isNone(maybe)) return;
|
|
163
|
+
const did = maybe.value.did;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Field reads change shape: `Identity.Info` is `{ did, displayName? }`.
|
|
167
|
+
`identityKey` / `spaceKey` (credential plumbing) are intentionally dropped in
|
|
168
|
+
favor of the DID.
|
|
169
|
+
|
|
170
|
+
### Identity — subscribe
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// Before
|
|
174
|
+
const sub = client.halo.identity.subscribe((identity) => onChange(identity));
|
|
175
|
+
// ... sub.unsubscribe();
|
|
176
|
+
|
|
177
|
+
// After — the same stream, subscribed instead of head-read; completes when the scope closes
|
|
178
|
+
yield * Stream.runForEach(Identity.identity, (maybe) => Effect.sync(() => onChange(maybe)));
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Identity — create / update profile
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
// Before
|
|
185
|
+
await client.halo.createIdentity({ displayName: 'Alice' });
|
|
186
|
+
await client.halo.updateProfile({ displayName: 'Alice B.' });
|
|
187
|
+
|
|
188
|
+
// After
|
|
189
|
+
const info = yield * Identity.create({ displayName: 'Alice', deviceLabel: 'laptop' });
|
|
190
|
+
yield * Identity.updateProfile({ displayName: 'Alice B.' });
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Devices
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// Before
|
|
197
|
+
const devices = client.halo.devices.get();
|
|
198
|
+
|
|
199
|
+
// After — Identity.devices is a current-value stream
|
|
200
|
+
const devices = yield * Stream.runHead(Identity.devices); // Option<readonly DeviceInfo[]> ({ key, kind?, label?, current })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`DeviceInfo.kind` is the inlined `Identity.DeviceKind` literal
|
|
204
|
+
(`'unknown' | 'browser' | 'native' | 'mobile' | 'agent' | 'agent-managed'`),
|
|
205
|
+
replacing the protobuf `DeviceType` enum. **Device _update_ is not defined** —
|
|
206
|
+
stay on the client for that.
|
|
207
|
+
|
|
208
|
+
### Spaces — list / get
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// Before
|
|
212
|
+
const spaces = client.spaces.get();
|
|
213
|
+
const space = getSpace(object) ?? client.spaces.get(spaceId);
|
|
214
|
+
|
|
215
|
+
// After — Space.spaces is a current-value stream; get is a point lookup
|
|
216
|
+
const spaces = yield * Stream.runHead(Space.spaces); // Option<readonly Space.Info[]>
|
|
217
|
+
const maybe = yield * Space.get(spaceId); // Option<Space.Info>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`Space.Info` is `{ id, name?, state }` — a snapshot. For `space.db` / query /
|
|
221
|
+
properties, use `@dxos/echo` keyed by `Space.Info.id`; do not expect a proxy.
|
|
222
|
+
|
|
223
|
+
### Spaces — create
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// Before
|
|
227
|
+
const space = await client.spaces.create({ name: 'Project' }, { tags: ['team'], membershipPolicy });
|
|
228
|
+
await space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED);
|
|
229
|
+
|
|
230
|
+
// After
|
|
231
|
+
const info = yield * Space.create({ name: 'Project', tags: ['team'], membershipPolicy: 'invite' });
|
|
232
|
+
yield * Space.setEdgeReplication(info.id, 'enabled');
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`membershipPolicy` is `'invite' | 'locked'` and `setEdgeReplication` takes
|
|
236
|
+
`'disabled' | 'enabled'` (the adapter maps the legacy protobuf enums). **Gap:**
|
|
237
|
+
`migrate` is intentionally not modeled — call sites needing it stay on the
|
|
238
|
+
client.
|
|
239
|
+
|
|
240
|
+
### Spaces — wait ready
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
// Before
|
|
244
|
+
await space.waitUntilReady();
|
|
245
|
+
|
|
246
|
+
// After
|
|
247
|
+
yield * Space.waitReady(spaceId);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Members
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
// Before
|
|
254
|
+
const members = space.members.get(); // SpaceMember[]
|
|
255
|
+
|
|
256
|
+
// After — Space.members(id) is a current-value stream
|
|
257
|
+
const members = yield * Stream.runHead(Space.members(spaceId)); // Option<readonly Space.Member[]> ({ did?, role, online })
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`Member.role` is the Keyhive-aligned `Space.Access`
|
|
261
|
+
(`'pull' | 'read' | 'edit' | 'admin'`); the adapter maps the legacy
|
|
262
|
+
`SpaceMember.Role` enum. `updateMemberRole(id, did, role)` and
|
|
263
|
+
`removeMember(id, did)` are defined (removal re-keys the space and does not
|
|
264
|
+
converge in the in-memory test harness — see the e2e NOTE).
|
|
265
|
+
|
|
266
|
+
### Export / import
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
// Before — via client space handle
|
|
270
|
+
// After
|
|
271
|
+
const archive = yield* Space.exportSpace(spaceId); // { filename, contents }
|
|
272
|
+
const info = yield* Space.importSpace(archive, { tags: [...] });
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Invitations — share (host)
|
|
276
|
+
|
|
277
|
+
Initiation lives on `Identity` / `Space` (not on `Invitation`); the returned
|
|
278
|
+
`Flow` is then driven through the `Invitation` verbs.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
// Before
|
|
282
|
+
const observable = space.share({ authMethod: Invitation.AuthMethod.NONE });
|
|
283
|
+
observable.subscribe((invitation) => {
|
|
284
|
+
/* switch on invitation.state */
|
|
285
|
+
});
|
|
286
|
+
const code = InvitationEncoder.encode(observable.get());
|
|
287
|
+
|
|
288
|
+
// After
|
|
289
|
+
const flow = yield * Space.share(spaceId, { authMethod: 'none' }); // Invitation.Flow
|
|
290
|
+
const code = yield * Invitation.code(flow);
|
|
291
|
+
yield *
|
|
292
|
+
Stream.runForEach(Invitation.events(flow), (event) =>
|
|
293
|
+
Effect.sync(() => {
|
|
294
|
+
// event._tag: 'connecting' | 'connected' | 'readyForAuthentication'
|
|
295
|
+
// | 'authenticating' | 'success' | 'cancelled' | 'error'
|
|
296
|
+
}),
|
|
297
|
+
);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Device invitations are identical with `Identity.share(options?)`.
|
|
301
|
+
|
|
302
|
+
### Invitations — join (guest) + authenticate
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
// Before
|
|
306
|
+
const observable = client.spaces.join(InvitationEncoder.decode(code));
|
|
307
|
+
observable.subscribe(/* ... */);
|
|
308
|
+
await observable.authenticate(authCode);
|
|
309
|
+
|
|
310
|
+
// After
|
|
311
|
+
const flow = yield * Space.join(code); // decodes internally
|
|
312
|
+
yield *
|
|
313
|
+
Stream.runForEach(Invitation.events(flow), (event) =>
|
|
314
|
+
event._tag === 'readyForAuthentication' ? Invitation.authenticate(flow, authCode) : Effect.void,
|
|
315
|
+
);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
`Identity.join(code)` is the device equivalent. `Invitation.cancel(flow)` aborts.
|
|
319
|
+
|
|
320
|
+
### Invitations — observe active flows
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
// Before
|
|
324
|
+
const invitations = space.invitations.get();
|
|
325
|
+
|
|
326
|
+
// After — querying lives on the owning service as a current-value stream
|
|
327
|
+
const flows = yield * Stream.runHead(Space.invitations(spaceId)); // device: Identity.invitations
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Drive an individual `Invitation.Flow` through the flow verbs (`Invitation.events`
|
|
331
|
+
/ `authenticate` / `cancel` / `code`), which need no service.
|
|
332
|
+
|
|
333
|
+
## What stays on `@dxos/client` (for now)
|
|
334
|
+
|
|
335
|
+
| Area | Reason | Unblocks when |
|
|
336
|
+
| --------------------------------------------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------ |
|
|
337
|
+
| `useCredentials` | no service verb yet | credential verbs added to `Identity` (the other HALO hooks now live in `@dxos/halo-react`) |
|
|
338
|
+
| `space.db` / `space.crud` / `space.properties` / `space.internal.*` (except edge replication) | ECHO, not HALO | migrate to the `@dxos/echo` `Database` service keyed by `SpaceId` |
|
|
339
|
+
| `halo.queryCredentials` / `writeCredentials`; recovery-credential _creation_ | deferred verb | credential + recovery verbs added to `Identity` |
|
|
340
|
+
| `createEdgeIdentity` / EDGE attestation | deferred verb | EDGE verbs added to `Identity` |
|
|
341
|
+
| device _update_ | deferred verb | `Identity` device-update verb added |
|
|
342
|
+
| `space.internal.migrate` | intentionally out of scope | (revisit if needed) |
|
|
343
|
+
| full `SpaceState` enum | `Space.State` is the consumer subset | (by design) |
|
package/LICENSE
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 DXOS
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|