@owlmeans/viable-common 0.0.48-rc.2 → 0.0.48-rc.4
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/README.md +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/agent-presentation/SKILL.md +1 -1
- package/agent-meta/skills/viable-common/SKILL.md +16 -7
- package/build/intent/consts.d.ts +14 -1
- package/build/intent/consts.d.ts.map +1 -1
- package/build/intent/consts.js +14 -1
- package/build/intent/consts.js.map +1 -1
- package/build/intent/entrypoints.d.ts +3 -2
- package/build/intent/entrypoints.d.ts.map +1 -1
- package/build/intent/entrypoints.js +5 -3
- package/build/intent/entrypoints.js.map +1 -1
- package/build/intent/types.d.ts +15 -0
- package/build/intent/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/intent/consts.ts +16 -1
- package/src/intent/entrypoints.ts +8 -3
- package/src/intent/types.ts +16 -0
- package/tests/intent.spec.ts +8 -4
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ the Viable platform has no use for it. The package's skills are `viable-common`
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
bun add @owlmeans/viable-common@^0.0.48-rc.
|
|
18
|
+
bun add @owlmeans/viable-common@^0.0.48-rc.4
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## What is in it
|
|
@@ -209,7 +209,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
209
209
|
your project's skill store (`.agents/skills/`):
|
|
210
210
|
|
|
211
211
|
```sh
|
|
212
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
212
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.56
|
|
213
213
|
```
|
|
214
214
|
|
|
215
215
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/viable-common",
|
|
4
|
-
"version": "0.0.48-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.0.48-rc.4",
|
|
5
|
+
"generatedAt": "2026-10-17T00:00:32.717Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -6,7 +6,7 @@ description: Shared, runtime-free taxonomy for presenting OwlMeans Viable agent
|
|
|
6
6
|
|
|
7
7
|
# Agent output presentation
|
|
8
8
|
|
|
9
|
-
**Install:** `"@owlmeans/viable-common": "^0.0.48-rc.
|
|
9
|
+
**Install:** `"@owlmeans/viable-common": "^0.0.48-rc.4"` in `dependencies`
|
|
10
10
|
|
|
11
11
|
`@owlmeans/viable-common`'s `agent/presentation.ts` owns the browser-safe vocabulary for agent
|
|
12
12
|
output. Keep the server and every client on `agentPresentationHelper.classifyAgentMessage()`; consumers may refine a
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/viable-common
|
|
9
9
|
|
|
10
10
|
**Layer:** Cross-cutting domain (contracts only)
|
|
11
|
-
**Install:** `"@owlmeans/viable-common": "^0.0.48-rc.
|
|
11
|
+
**Install:** `"@owlmeans/viable-common": "^0.0.48-rc.4"` in `dependencies`
|
|
12
12
|
**Subpaths:** `.` · `./slot` · `./connect` · `./convert` · `./integrity` · `./intent` · `./legal` · `./iam-console` — the barrel
|
|
13
13
|
re-exports every subpath except `./intent`.
|
|
14
14
|
**Runtime-free:** no `@langchain/*`, no filesystem, no Ajv at run time (a devDependency, for the
|
|
@@ -36,7 +36,7 @@ execution state and card fields name.
|
|
|
36
36
|
| `./connect` | `ConnectTarget`, `ConnectLlm`, `ConnectHarness`, `ConnectExecutor`, `ConnectOpKind`, `ConnectProjectStatus`, `ConnectStoryStatus`, `ConnectPipelineState`, `ConnectWaitReason`, `ConnectProjectBranding` / `ConnectProjectBrandingSave` / `ConnectProjectBrandingFields` / `ConnectBrandingCredit` / `ConnectBrandingCreditBody`, the configuration contract (`ConnectScopeQuery`, `ConnectConfigScope`, `ConnectProjectConfig`, `ConnectConfigVariable`, `ConnectFrontendVariable`, `ConnectConfigValue`, `ConnectConfigSaveBody`, `CONNECT_CONFIG_*`), the organization's defaults (`ConnectOrganizationBranding(Save)`, `ConnectBrandingBackfill`), the planning-kit views (`PlanningKitView`, `ConnectKitDescribe`, `ConnectKitApplyBody`, `ConnectKitApplyResult` and their `*Schema`s), `ModelTier` + `modelTierHelper` (`tierOfRole`/`clampTier`), `ModelTask*`, `InquiryPayload` + `ConnectInquiryKind`, the session and domain-status views, the convert bodies (`ConnectConvertCreateBody`, `ConnectConvertStartBody`, `ConnectConvertProceedBody` + `ConnectConvertProceedUpdate`), `ConnectAgentLock`, `ConnectPaidGate` + `ConnectGateRef` + `ConnectEntrypointOptions`, the call collection (`CONNECT_CALL_HEADER`, `CONNECT_CALL_ACCEPT_MS`, `CONNECT_CALL_COLLECT_WAIT_SEC`, `CONNECT_CALL_LOST_MS`, `ConnectCallState`, `ConnectCallPending`, `ConnectCallResult`, `ConnectCallCollectParams` / `ConnectCallCollectQuery` and their `*Schema`s), the `Connect*` error family with `ConnectConfirmation` / `ConnectConfirmationAction`, `connectProtocols(opts)` and every `*Schema` behind them |
|
|
37
37
|
| `./convert` | `ConversionStage`/`Status`/`Decision` and the `conversionStageHelper` transitions (`stageAfter`/`decisionFor`/`canEnter`), `OriginKind`/`OriginShape`/`OriginState`, `StackId` + `STACK_FAMILY`, `ArchitectureCase`, `ConvertibilityVerdict`/`ConvertibilityReason`, the census classifiers (`censusHelper` — `fileClassOf`, `sizeClassOf`, `entropyClassOf`, `binaryByExtension`), the `docs/conversion/` paths, `CONVERTED_ORIGIN_DIR`, `SOURCE_LIST_EXCLUSIONS`, `CENSUS_SKIP_DIRS`, `RELOCATE_ALWAYS_KEEP`, and the model-answer schemas the conversion asks with |
|
|
38
38
|
| `./integrity` | `TargetLayout` + `TARGET_LAYOUTS`, `targetLayoutHelper` (`detectTargetLayout`, `isLegacyLayout`, `targetPackageName`), `targetIntegrityHelper.verifyTargetShape`, `TARGET_INTEGRITY_FILES`, `TARGET_PROTECTED_FILES` |
|
|
39
|
-
| `./intent` | `intent` (the
|
|
39
|
+
| `./intent` | `intent` (the five aliases), `makeIntentProtocols(opts?)`, `intentFlow` + `IntentFlowStep` + `INTENT_PAYLOAD_REF`, `IntentStashBodySchema` / `IntentPickupBodySchema`, the `INTENT_*` constants (`INTENT_IMPORT_PATH`, `INTENT_IMPORT_KIND` included), `IntentDraft` / `IntentImportDraft`, `IntentExpired` (404) / `IntentThrottled` (429) |
|
|
40
40
|
| `./iam-console` | The owner console's IAM contract both doors share (the browser's `back.iam`, the connector's `connect.iam`): the route params (`IamProjectParams`, `IamProjectUserParams`, `IamOrganizationParams`, `IamMemberParams`, `IamGroupParams`), `IamScoped`, the bodies (`IamDefinitionUpdate`, `IamStaffSync`, `IamAssignGrant` / `IamRevokeGrant`, `IamGrantsQuery`, `IamProjectUserInvite` / `Update`, `IamOrganizationEdit`, `IamProjectMemberInvite` / `Update`, `IamGroupCreate` / `Edit`, `IamGroupMembersChange`), the answers (`IamListResponse` + `external`, `IamUsersResponse`, `IamPermissionsResponse` + `IamTenancy`, …, `IamStaffSyncResponse`), every `Iam*Schema` (with `IamScopedSchema`, `IamGroupRefSchema`), `IAM_REFUSED`, and the `@owlmeans/iam` vocabulary re-exported (`IamDefaultClass`, `IamGrantMode`, `IamGrantOrigin`, `IamRemovalPolicy`, `IAM_AREAS`, `IAM_MEMBERS_GROUP`, the record types). The refusal's CLASS (`IamRefused`, 409) is the platform's |
|
|
41
41
|
| `./legal` | `OWLMEANS_LEGAL_DATES`, `LegalDocumentDates`, `PendingLegalDocumentDates`, `LegalDocumentDateMetadata`, `LegalDocumentKey` — active dates and pending metadata for public legal sources and acceptance |
|
|
42
42
|
|
|
@@ -412,10 +412,11 @@ platform through this subpath: the site, the API services (stash and pickup may
|
|
|
412
412
|
different ones) and the manager web agree on every address, schema and step. Platform side:
|
|
413
413
|
`/intent-first`.
|
|
414
414
|
|
|
415
|
-
- **Two guest routes and
|
|
415
|
+
- **Two guest routes and two screens, no guard, no gate, no service.** `stash` POST
|
|
416
416
|
`/public/intent` (`{ prompt 1..INTENT_PROMPT_MAX (8192), consent: const true }` →
|
|
417
417
|
`{ ref, expiresAt }`), `pickup` POST `/public/intent/pickup` (`{ ref }`, exactly
|
|
418
|
-
`INTENT_REF_LENGTH` (24) Base58 → `{ prompt }`), `landing` (`frontend()` at `/start`, `sticky`)
|
|
418
|
+
`INTENT_REF_LENGTH` (24) Base58 → `{ prompt }`), `landing` (`frontend()` at `/start`, `sticky`) and
|
|
419
|
+
`importLanding` (`frontend()` at `INTENT_IMPORT_PATH` = `/start/import`, `sticky`).
|
|
419
420
|
Mount the tree OUTSIDE any guarded parent (a route inherits every ancestor's guard) and fill
|
|
420
421
|
`service` yourself (the site binds `landing` with `{ routeOptions: { overrides: { service } } }`,
|
|
421
422
|
which also makes its `url()` absolute).
|
|
@@ -429,9 +430,17 @@ different ones) and the manager web agree on every address, schema and step. Pla
|
|
|
429
430
|
parses it on every page load) and never `?intent=` (the login surrogate window owns it).
|
|
430
431
|
- **CORS is not declared here**: the routes ride the global `origin: '*'` (no credentials);
|
|
431
432
|
`makeIntentProtocols` carries a `TODO(cors)` naming the origins to keep if that is restricted.
|
|
432
|
-
- **The
|
|
433
|
-
|
|
434
|
-
(`
|
|
433
|
+
- **The second intent — import an existing project — is a plain link, no stash.** The visitor
|
|
434
|
+
brings no text, so the site links straight to `importLanding` (its absolute URL is
|
|
435
|
+
`new URL(INTENT_IMPORT_PATH, <platform web>)`); nothing crosses but the consent linker's `owlcc`.
|
|
436
|
+
`intentFlow` is not walked for it: its `land` step is `/start`, and the import landing needs only
|
|
437
|
+
the way on after sign-in, which is `HOME` for both.
|
|
438
|
+
- **The browser draft is IndexedDB, per origin — ONE record slot for both intents.** `IntentDraft`
|
|
439
|
+
(`id`, `ref`, `prompt`, `expiresAt`) is kept between pickup and decision (`INTENT_DRAFT_TTL_MS`,
|
|
440
|
+
24 h); `IntentImportDraft` (`id`, `kind: INTENT_IMPORT_KIND`, `expiresAt`) holds the import wish
|
|
441
|
+
for `INTENT_SUSPEND_TTL_MS` (30 min — the sign-in it rides through). The newest intent replaces the
|
|
442
|
+
other; a record is an import iff its `kind` says so (a prompt draft carries none). Expiry is
|
|
443
|
+
checked on read.
|
|
435
444
|
|
|
436
445
|
## Slot metadata keys: optional means omitted
|
|
437
446
|
|
package/build/intent/consts.d.ts
CHANGED
|
@@ -18,10 +18,20 @@ export declare const intent: Readonly<{
|
|
|
18
18
|
readonly stash: 'viable:manager-api:intent:stash';
|
|
19
19
|
readonly pickup: 'viable:manager-api:intent:pickup';
|
|
20
20
|
readonly landing: 'viable:manager-web:intent:landing';
|
|
21
|
+
readonly importLanding: 'viable:manager-web:intent:import';
|
|
21
22
|
}>;
|
|
22
23
|
/** Where the guest API lives, and the screen the visitor's browser is sent to. */
|
|
23
24
|
export declare const INTENT_API_PATH = "/public/intent";
|
|
24
25
|
export declare const INTENT_LANDING_PATH = "/start";
|
|
26
|
+
/**
|
|
27
|
+
* The second way in: the public site's "Import from GitHub" is a plain link to this screen. There
|
|
28
|
+
* is nothing to stash — the visitor brings no text, only the wish — so no guest API call and no
|
|
29
|
+
* reference; the platform records the wish in the visitor's browser and opens its import dialog on
|
|
30
|
+
* the home screen once they are signed in.
|
|
31
|
+
*/
|
|
32
|
+
export declare const INTENT_IMPORT_PATH = "/start/import";
|
|
33
|
+
/** `kind` of the browser record an import wish waits in ({@link IntentImportDraft}). */
|
|
34
|
+
export declare const INTENT_IMPORT_KIND = "import";
|
|
25
35
|
/** The flow the two sides walk. */
|
|
26
36
|
export declare const INTENT_FLOW = "viable:intent";
|
|
27
37
|
/**
|
|
@@ -42,7 +52,10 @@ export declare const INTENT_REF_PATTERN = "^[1-9A-HJ-NP-Za-km-z]{24}$";
|
|
|
42
52
|
export declare const INTENT_PAYLOAD_REF = "ref";
|
|
43
53
|
/** How long the visitor's draft survives in their own browser waiting for a decision. */
|
|
44
54
|
export declare const INTENT_DRAFT_TTL_MS: number;
|
|
45
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* How long a suspended landing waits while the visitor signs in or registers — and how long an
|
|
57
|
+
* import wish waits in the browser: it belongs to that sign-in, not to a later visit.
|
|
58
|
+
*/
|
|
46
59
|
export declare const INTENT_SUSPEND_TTL_MS: number;
|
|
47
60
|
/** Steps of {@link intentFlow}, exported so a screen never spells one as a literal. */
|
|
48
61
|
export declare enum IntentFlowStep {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/intent/consts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,2FAA2F;AAC3F,eAAO,MAAM,MAAM;mBACX,gCAAgC;oBAC/B,iCAAiC;qBAChC,kCAAkC;sBACjC,mCAAmC;
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/intent/consts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,2FAA2F;AAC3F,eAAO,MAAM,MAAM;mBACX,gCAAgC;oBAC/B,iCAAiC;qBAChC,kCAAkC;sBACjC,mCAAmC;4BAC7B,kCAAkC;EACxC,CAAA;AAEX,kFAAkF;AAClF,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAC/C,eAAO,MAAM,mBAAmB,WAAW,CAAA;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,kBAAkB,CAAA;AAEjD,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C,mCAAmC;AACnC,eAAO,MAAM,WAAW,kBAAkB,CAAA;AAE1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAA;AACnC,eAAO,MAAM,kBAAkB,+BAA+B,CAAA;AAE9D,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,QAAQ,CAAA;AAEvC,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,QAAsB,CAAA;AAEtD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AAEnD,uFAAuF;AACvF,oBAAY,cAAc;IACxB,wDAAwD;IACxD,OAAO,YAAY;IACnB,6DAA6D;IAC7D,IAAI,SAAS;IACb,6CAA6C;IAC7C,MAAM,YAAY;IAClB,mEAAmE;IACnE,MAAM,WAAW;CAClB;AAID;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,UAAU,EAAE,WA6CxB,CAAA"}
|
package/build/intent/consts.js
CHANGED
|
@@ -19,10 +19,20 @@ export const intent = Object.freeze({
|
|
|
19
19
|
stash: 'viable:manager-api:intent:stash',
|
|
20
20
|
pickup: 'viable:manager-api:intent:pickup',
|
|
21
21
|
landing: 'viable:manager-web:intent:landing',
|
|
22
|
+
importLanding: 'viable:manager-web:intent:import',
|
|
22
23
|
});
|
|
23
24
|
/** Where the guest API lives, and the screen the visitor's browser is sent to. */
|
|
24
25
|
export const INTENT_API_PATH = '/public/intent';
|
|
25
26
|
export const INTENT_LANDING_PATH = '/start';
|
|
27
|
+
/**
|
|
28
|
+
* The second way in: the public site's "Import from GitHub" is a plain link to this screen. There
|
|
29
|
+
* is nothing to stash — the visitor brings no text, only the wish — so no guest API call and no
|
|
30
|
+
* reference; the platform records the wish in the visitor's browser and opens its import dialog on
|
|
31
|
+
* the home screen once they are signed in.
|
|
32
|
+
*/
|
|
33
|
+
export const INTENT_IMPORT_PATH = '/start/import';
|
|
34
|
+
/** `kind` of the browser record an import wish waits in ({@link IntentImportDraft}). */
|
|
35
|
+
export const INTENT_IMPORT_KIND = 'import';
|
|
26
36
|
/** The flow the two sides walk. */
|
|
27
37
|
export const INTENT_FLOW = 'viable:intent';
|
|
28
38
|
/**
|
|
@@ -43,7 +53,10 @@ export const INTENT_REF_PATTERN = '^[1-9A-HJ-NP-Za-km-z]{24}$';
|
|
|
43
53
|
export const INTENT_PAYLOAD_REF = 'ref';
|
|
44
54
|
/** How long the visitor's draft survives in their own browser waiting for a decision. */
|
|
45
55
|
export const INTENT_DRAFT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
46
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* How long a suspended landing waits while the visitor signs in or registers — and how long an
|
|
58
|
+
* import wish waits in the browser: it belongs to that sign-in, not to a later visit.
|
|
59
|
+
*/
|
|
47
60
|
export const INTENT_SUSPEND_TTL_MS = 30 * 60 * 1000;
|
|
48
61
|
/** Steps of {@link intentFlow}, exported so a screen never spells one as a literal. */
|
|
49
62
|
export var IntentFlowStep;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/intent/consts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAGxC,2FAA2F;AAC3F,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,gCAAgC;IACtC,KAAK,EAAE,iCAAiC;IACxC,MAAM,EAAE,kCAAkC;IAC1C,OAAO,EAAE,mCAAmC;
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/intent/consts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IntentProtocolOptions, IntentProtocols } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Declare the intent-first hand-off: two GUEST API routes and the landing
|
|
3
|
+
* Declare the intent-first hand-off: two GUEST API routes and the two landing screens' addresses —
|
|
4
|
+
* `/start` for a stashed prompt, `/start/import` for the wish to import an existing project.
|
|
4
5
|
*
|
|
5
6
|
* No guard and no gate anywhere on the API — the caller is a visitor who has no account yet — and
|
|
6
7
|
* no `service` on any route: each consumer fills it in (the public site names the platform's
|
|
@@ -10,7 +11,7 @@ import type { IntentProtocolOptions, IntentProtocols } from './types.js';
|
|
|
10
11
|
* If viable ever restricts allowed origins globally, this entrypoint must keep answering the public
|
|
11
12
|
* site's origins — owlmeans.com, owlmeans.pl and, in dev/stage, `http://localhost:4321`.
|
|
12
13
|
*
|
|
13
|
-
* The landing
|
|
14
|
+
* The landing screens are `sticky`, like the OAuth consent screens: it is an ordinary in-app screen
|
|
14
15
|
* that a visitor arrives at directly from another origin.
|
|
15
16
|
*/
|
|
16
17
|
export declare const makeIntentProtocols: (opts?: IntentProtocolOptions) => IntentProtocols;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/intent/entrypoints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAC4B,qBAAqB,EAAE,eAAe,EAC7E,MAAM,YAAY,CAAA;AAEnB
|
|
1
|
+
{"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/intent/entrypoints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAC4B,qBAAqB,EAAE,eAAe,EAC7E,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,UAAU,qBAAqB,KAAQ,eAsBtE,CAAA"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { contract, openProtocol, protocol, typed } from '@owlmeans/entrypoint';
|
|
2
2
|
import { frontend, route, RouteMethod } from '@owlmeans/route';
|
|
3
|
-
import { INTENT_API_PATH, INTENT_LANDING_PATH, intent } from './consts.js';
|
|
3
|
+
import { INTENT_API_PATH, INTENT_IMPORT_PATH, INTENT_LANDING_PATH, intent } from './consts.js';
|
|
4
4
|
import { IntentPickupBodySchema, IntentStashBodySchema } from './schemas.js';
|
|
5
5
|
/**
|
|
6
|
-
* Declare the intent-first hand-off: two GUEST API routes and the landing
|
|
6
|
+
* Declare the intent-first hand-off: two GUEST API routes and the two landing screens' addresses —
|
|
7
|
+
* `/start` for a stashed prompt, `/start/import` for the wish to import an existing project.
|
|
7
8
|
*
|
|
8
9
|
* No guard and no gate anywhere on the API — the caller is a visitor who has no account yet — and
|
|
9
10
|
* no `service` on any route: each consumer fills it in (the public site names the platform's
|
|
@@ -13,7 +14,7 @@ import { IntentPickupBodySchema, IntentStashBodySchema } from './schemas.js';
|
|
|
13
14
|
* If viable ever restricts allowed origins globally, this entrypoint must keep answering the public
|
|
14
15
|
* site's origins — owlmeans.com, owlmeans.pl and, in dev/stage, `http://localhost:4321`.
|
|
15
16
|
*
|
|
16
|
-
* The landing
|
|
17
|
+
* The landing screens are `sticky`, like the OAuth consent screens: it is an ordinary in-app screen
|
|
17
18
|
* that a visitor arrives at directly from another origin.
|
|
18
19
|
*/
|
|
19
20
|
export const makeIntentProtocols = (opts = {}) => {
|
|
@@ -23,6 +24,7 @@ export const makeIntentProtocols = (opts = {}) => {
|
|
|
23
24
|
stash: protocol(route(intent.stash, '/', { parent: base, method: RouteMethod.POST }), contract.request({ body: typed(IntentStashBodySchema) }, typed())),
|
|
24
25
|
pickup: protocol(route(intent.pickup, '/pickup', { parent: base, method: RouteMethod.POST }), contract.request({ body: typed(IntentPickupBodySchema) }, typed())),
|
|
25
26
|
landing: openProtocol(route(intent.landing, opts.landing ?? INTENT_LANDING_PATH, frontend()), { sticky: true }),
|
|
27
|
+
importLanding: openProtocol(route(intent.importLanding, opts.importLanding ?? INTENT_IMPORT_PATH, frontend()), { sticky: true }),
|
|
26
28
|
};
|
|
27
29
|
};
|
|
28
30
|
//# sourceMappingURL=entrypoints.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../../src/intent/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../../src/intent/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAK5E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,GAA0B,EAAE,EAAmB,EAAE;IACvF,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,eAAe,CAAC,CAAC,CAAA;IAE3E,OAAO;QACL,IAAI;QAEJ,KAAK,EAAE,QAAQ,CACb,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,EACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,CAAkB,qBAAqB,CAAC,EAAE,EAAE,KAAK,EAAqB,CAAC,CACtG;QAED,MAAM,EAAE,QAAQ,CACd,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,EAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,CAAmB,sBAAsB,CAAC,EAAE,EAAE,KAAK,EAAsB,CAAC,CACzG;QAED,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,mBAAmB,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAE/G,aAAa,EAAE,YAAY,CACzB,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CACpG;KACF,CAAA;AACH,CAAC,CAAA"}
|
package/build/intent/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EntrypointProtocol, OpenRequest, OpenValue } from '@owlmeans/entrypoint';
|
|
2
2
|
import type { ResourceRecord } from '@owlmeans/resource';
|
|
3
|
+
import type { INTENT_IMPORT_KIND } from './consts.js';
|
|
3
4
|
/** What the public site sends: the prompt and the person's confirmation of its processing. */
|
|
4
5
|
export interface IntentStashBody {
|
|
5
6
|
prompt: string;
|
|
@@ -29,6 +30,16 @@ export interface IntentDraft extends ResourceRecord {
|
|
|
29
30
|
prompt: string;
|
|
30
31
|
expiresAt: number;
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* The wish to import an existing project, waiting in the visitor's browser between the import
|
|
35
|
+
* landing and the home screen. It shares {@link IntentDraft}'s record slot, so the visitor's NEWEST
|
|
36
|
+
* intent is the one acted on; `kind` tells the two apart (a prompt draft carries none).
|
|
37
|
+
*/
|
|
38
|
+
export interface IntentImportDraft extends ResourceRecord {
|
|
39
|
+
id: string;
|
|
40
|
+
kind: typeof INTENT_IMPORT_KIND;
|
|
41
|
+
expiresAt: number;
|
|
42
|
+
}
|
|
32
43
|
/**
|
|
33
44
|
* Options of {@link makeIntentProtocols}.
|
|
34
45
|
*/
|
|
@@ -37,6 +48,8 @@ export interface IntentProtocolOptions {
|
|
|
37
48
|
path?: string;
|
|
38
49
|
/** Path of the landing screen; defaults to `/start`. */
|
|
39
50
|
landing?: string;
|
|
51
|
+
/** Path of the import landing screen; defaults to `/start/import`. */
|
|
52
|
+
importLanding?: string;
|
|
40
53
|
}
|
|
41
54
|
/** The intent-first hand-off tree {@link makeIntentProtocols} declares. */
|
|
42
55
|
export interface IntentProtocols {
|
|
@@ -49,5 +62,7 @@ export interface IntentProtocols {
|
|
|
49
62
|
}, IntentPickupResult>;
|
|
50
63
|
/** The landing screen — `sticky`, an in-app screen a visitor reaches from another origin. */
|
|
51
64
|
landing: EntrypointProtocol<OpenRequest, OpenValue>;
|
|
65
|
+
/** The import landing screen — `sticky` too; reached by a plain link, no stash. */
|
|
66
|
+
importLanding: EntrypointProtocol<OpenRequest, OpenValue>;
|
|
52
67
|
}
|
|
53
68
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,0FAA0F;IAC1F,OAAO,EAAE,IAAI,CAAA;CACd;AAED,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,EAAE,EAAE,MAAM,CAAA;IACV,iGAAiG;IACjG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,kBAAkB,CAAA;IAC/B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,kBAAkB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IAChD,KAAK,EAAE,kBAAkB,CAAC;QAAE,IAAI,EAAE,eAAe,CAAA;KAAE,EAAE,iBAAiB,CAAC,CAAA;IACvE,MAAM,EAAE,kBAAkB,CAAC;QAAE,IAAI,EAAE,gBAAgB,CAAA;KAAE,EAAE,kBAAkB,CAAC,CAAA;IAC1E,6FAA6F;IAC7F,OAAO,EAAE,kBAAkB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IACnD,mFAAmF;IACnF,aAAa,EAAE,kBAAkB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;CAC1D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/viable-common",
|
|
3
|
-
"version": "0.0.48-rc.
|
|
3
|
+
"version": "0.0.48-rc.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Runtime-free contracts of the OwlMeans Viable platform — the analysis, design and metadata shapes of a generated project, its target-shape manifest, the slot command vocabulary, the connector protocol, the owner console's IAM contract and the conversion vocabulary, and the intent-first hand-off from the public site to the platform.",
|
|
6
6
|
"type": "module",
|
|
@@ -82,14 +82,14 @@
|
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@owlmeans/agent-common": "^0.1.18-rc.49",
|
|
84
84
|
"@owlmeans/auth": "^0.1.18-rc.41",
|
|
85
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
85
|
+
"@owlmeans/auth-common": "^0.1.18-rc.51",
|
|
86
86
|
"@owlmeans/context": "^0.1.18-rc.34",
|
|
87
87
|
"@owlmeans/entrypoint": "^0.1.18-rc.41",
|
|
88
88
|
"@owlmeans/error": "^0.1.18-rc.38",
|
|
89
89
|
"@owlmeans/flow": "^0.1.18-rc.45",
|
|
90
|
-
"@owlmeans/iam": "^0.1.18-rc.
|
|
90
|
+
"@owlmeans/iam": "^0.1.18-rc.54",
|
|
91
91
|
"@owlmeans/llm-common": "^0.1.18-rc.39",
|
|
92
|
-
"@owlmeans/planning": "^0.1.18-rc.
|
|
92
|
+
"@owlmeans/planning": "^0.1.18-rc.28",
|
|
93
93
|
"@owlmeans/resource": "^0.1.18-rc.40",
|
|
94
94
|
"@owlmeans/route": "^0.1.18-rc.35"
|
|
95
95
|
},
|
package/src/intent/consts.ts
CHANGED
|
@@ -22,12 +22,24 @@ export const intent = Object.freeze({
|
|
|
22
22
|
stash: 'viable:manager-api:intent:stash',
|
|
23
23
|
pickup: 'viable:manager-api:intent:pickup',
|
|
24
24
|
landing: 'viable:manager-web:intent:landing',
|
|
25
|
+
importLanding: 'viable:manager-web:intent:import',
|
|
25
26
|
} as const)
|
|
26
27
|
|
|
27
28
|
/** Where the guest API lives, and the screen the visitor's browser is sent to. */
|
|
28
29
|
export const INTENT_API_PATH = '/public/intent'
|
|
29
30
|
export const INTENT_LANDING_PATH = '/start'
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* The second way in: the public site's "Import from GitHub" is a plain link to this screen. There
|
|
34
|
+
* is nothing to stash — the visitor brings no text, only the wish — so no guest API call and no
|
|
35
|
+
* reference; the platform records the wish in the visitor's browser and opens its import dialog on
|
|
36
|
+
* the home screen once they are signed in.
|
|
37
|
+
*/
|
|
38
|
+
export const INTENT_IMPORT_PATH = '/start/import'
|
|
39
|
+
|
|
40
|
+
/** `kind` of the browser record an import wish waits in ({@link IntentImportDraft}). */
|
|
41
|
+
export const INTENT_IMPORT_KIND = 'import'
|
|
42
|
+
|
|
31
43
|
/** The flow the two sides walk. */
|
|
32
44
|
export const INTENT_FLOW = 'viable:intent'
|
|
33
45
|
|
|
@@ -54,7 +66,10 @@ export const INTENT_PAYLOAD_REF = 'ref'
|
|
|
54
66
|
/** How long the visitor's draft survives in their own browser waiting for a decision. */
|
|
55
67
|
export const INTENT_DRAFT_TTL_MS = 24 * 60 * 60 * 1000
|
|
56
68
|
|
|
57
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* How long a suspended landing waits while the visitor signs in or registers — and how long an
|
|
71
|
+
* import wish waits in the browser: it belongs to that sign-in, not to a later visit.
|
|
72
|
+
*/
|
|
58
73
|
export const INTENT_SUSPEND_TTL_MS = 30 * 60 * 1000
|
|
59
74
|
|
|
60
75
|
/** Steps of {@link intentFlow}, exported so a screen never spells one as a literal. */
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { contract, openProtocol, protocol, typed } from '@owlmeans/entrypoint'
|
|
2
2
|
import { frontend, route, RouteMethod } from '@owlmeans/route'
|
|
3
|
-
import { INTENT_API_PATH, INTENT_LANDING_PATH, intent } from './consts.js'
|
|
3
|
+
import { INTENT_API_PATH, INTENT_IMPORT_PATH, INTENT_LANDING_PATH, intent } from './consts.js'
|
|
4
4
|
import { IntentPickupBodySchema, IntentStashBodySchema } from './schemas.js'
|
|
5
5
|
import type {
|
|
6
6
|
IntentPickupBody, IntentPickupResult, IntentProtocolOptions, IntentProtocols, IntentStashBody, IntentStashResult,
|
|
7
7
|
} from './types.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Declare the intent-first hand-off: two GUEST API routes and the landing
|
|
10
|
+
* Declare the intent-first hand-off: two GUEST API routes and the two landing screens' addresses —
|
|
11
|
+
* `/start` for a stashed prompt, `/start/import` for the wish to import an existing project.
|
|
11
12
|
*
|
|
12
13
|
* No guard and no gate anywhere on the API — the caller is a visitor who has no account yet — and
|
|
13
14
|
* no `service` on any route: each consumer fills it in (the public site names the platform's
|
|
@@ -17,7 +18,7 @@ import type {
|
|
|
17
18
|
* If viable ever restricts allowed origins globally, this entrypoint must keep answering the public
|
|
18
19
|
* site's origins — owlmeans.com, owlmeans.pl and, in dev/stage, `http://localhost:4321`.
|
|
19
20
|
*
|
|
20
|
-
* The landing
|
|
21
|
+
* The landing screens are `sticky`, like the OAuth consent screens: it is an ordinary in-app screen
|
|
21
22
|
* that a visitor arrives at directly from another origin.
|
|
22
23
|
*/
|
|
23
24
|
export const makeIntentProtocols = (opts: IntentProtocolOptions = {}): IntentProtocols => {
|
|
@@ -37,6 +38,10 @@ export const makeIntentProtocols = (opts: IntentProtocolOptions = {}): IntentPro
|
|
|
37
38
|
),
|
|
38
39
|
|
|
39
40
|
landing: openProtocol(route(intent.landing, opts.landing ?? INTENT_LANDING_PATH, frontend()), { sticky: true }),
|
|
41
|
+
|
|
42
|
+
importLanding: openProtocol(
|
|
43
|
+
route(intent.importLanding, opts.importLanding ?? INTENT_IMPORT_PATH, frontend()), { sticky: true },
|
|
44
|
+
),
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
47
|
|
package/src/intent/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EntrypointProtocol, OpenRequest, OpenValue } from '@owlmeans/entrypoint'
|
|
2
2
|
import type { ResourceRecord } from '@owlmeans/resource'
|
|
3
|
+
import type { INTENT_IMPORT_KIND } from './consts.js'
|
|
3
4
|
|
|
4
5
|
/** What the public site sends: the prompt and the person's confirmation of its processing. */
|
|
5
6
|
export interface IntentStashBody {
|
|
@@ -35,6 +36,17 @@ export interface IntentDraft extends ResourceRecord {
|
|
|
35
36
|
expiresAt: number
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The wish to import an existing project, waiting in the visitor's browser between the import
|
|
41
|
+
* landing and the home screen. It shares {@link IntentDraft}'s record slot, so the visitor's NEWEST
|
|
42
|
+
* intent is the one acted on; `kind` tells the two apart (a prompt draft carries none).
|
|
43
|
+
*/
|
|
44
|
+
export interface IntentImportDraft extends ResourceRecord {
|
|
45
|
+
id: string
|
|
46
|
+
kind: typeof INTENT_IMPORT_KIND
|
|
47
|
+
expiresAt: number
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
/**
|
|
39
51
|
* Options of {@link makeIntentProtocols}.
|
|
40
52
|
*/
|
|
@@ -43,6 +55,8 @@ export interface IntentProtocolOptions {
|
|
|
43
55
|
path?: string
|
|
44
56
|
/** Path of the landing screen; defaults to `/start`. */
|
|
45
57
|
landing?: string
|
|
58
|
+
/** Path of the import landing screen; defaults to `/start/import`. */
|
|
59
|
+
importLanding?: string
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
/** The intent-first hand-off tree {@link makeIntentProtocols} declares. */
|
|
@@ -52,4 +66,6 @@ export interface IntentProtocols {
|
|
|
52
66
|
pickup: EntrypointProtocol<{ body: IntentPickupBody }, IntentPickupResult>
|
|
53
67
|
/** The landing screen — `sticky`, an in-app screen a visitor reaches from another origin. */
|
|
54
68
|
landing: EntrypointProtocol<OpenRequest, OpenValue>
|
|
69
|
+
/** The import landing screen — `sticky` too; reached by a plain link, no stash. */
|
|
70
|
+
importLanding: EntrypointProtocol<OpenRequest, OpenValue>
|
|
55
71
|
}
|
package/tests/intent.spec.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { makeFlowModel } from '@owlmeans/flow'
|
|
|
8
8
|
import { AppType } from '@owlmeans/context'
|
|
9
9
|
import { RouteMethod } from '@owlmeans/route'
|
|
10
10
|
import {
|
|
11
|
-
INTENT_PAYLOAD_REF, INTENT_PROMPT_MAX, INTENT_TTL_SECONDS, IntentExpired, IntentFlowStep,
|
|
11
|
+
INTENT_IMPORT_PATH, INTENT_PAYLOAD_REF, INTENT_PROMPT_MAX, INTENT_TTL_SECONDS, IntentExpired, IntentFlowStep,
|
|
12
12
|
IntentPickupBodySchema, IntentStashBodySchema, IntentThrottled, intent, intentFlow, makeIntentProtocols,
|
|
13
13
|
} from '../src/intent/index.js'
|
|
14
14
|
|
|
@@ -24,13 +24,14 @@ const createIdOfLength = (length: number): string =>
|
|
|
24
24
|
describe('@owlmeans/viable-common — intent-first hand-off', () => {
|
|
25
25
|
const tree = makeIntentProtocols()
|
|
26
26
|
|
|
27
|
-
test('declares one guest base, two guest routes and
|
|
27
|
+
test('declares one guest base, two guest routes and two landing screens — no guard, no gate, no service', () => {
|
|
28
28
|
expect(tree.base.alias).toBe(intent.base)
|
|
29
29
|
expect(tree.stash.alias).toBe(intent.stash)
|
|
30
30
|
expect(tree.pickup.alias).toBe(intent.pickup)
|
|
31
31
|
expect(tree.landing.alias).toBe(intent.landing)
|
|
32
|
-
expect(
|
|
33
|
-
|
|
32
|
+
expect(tree.importLanding.alias).toBe(intent.importLanding)
|
|
33
|
+
expect(new Set(protocols(tree).map(protocol => protocol.alias)).size).toBe(5)
|
|
34
|
+
for (const declaration of [tree.base, tree.stash, tree.pickup, tree.landing, tree.importLanding]) {
|
|
34
35
|
expect(declaration.guards ?? []).toEqual([])
|
|
35
36
|
expect(declaration.gate).toBeUndefined()
|
|
36
37
|
expect(declaration.route.route.service).toBeUndefined()
|
|
@@ -40,6 +41,9 @@ describe('@owlmeans/viable-common — intent-first hand-off', () => {
|
|
|
40
41
|
expect(tree.pickup.route.route.path).toBe('/pickup')
|
|
41
42
|
expect(tree.landing.route.route.path).toBe('/start')
|
|
42
43
|
expect(tree.landing.route.route.type).toBe(AppType.Frontend)
|
|
44
|
+
expect(tree.importLanding.route.route.path).toBe(INTENT_IMPORT_PATH)
|
|
45
|
+
expect(tree.importLanding.route.route.type).toBe(AppType.Frontend)
|
|
46
|
+
expect(tree.importLanding.route.route.parent).toBeUndefined()
|
|
43
47
|
expect(aliasOf(tree.stash)).toBe(intent.stash)
|
|
44
48
|
})
|
|
45
49
|
|