@voyant-travel/apps 0.9.0 → 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/dist/api-runtime.js +14 -1
- package/dist/api-runtime.test.js +72 -5
- package/dist/compiler.test.js +11 -0
- package/dist/contracts.d.ts +2 -0
- package/dist/contracts.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/installation-routes.test.js +35 -1
- package/dist/installation-service.d.ts +1 -1
- package/dist/marketplace-acquisition.d.ts +93 -0
- package/dist/marketplace-acquisition.js +410 -0
- package/dist/marketplace-acquisition.test.d.ts +1 -0
- package/dist/marketplace-acquisition.test.js +191 -0
- package/dist/oauth-redirect.d.ts +6 -0
- package/dist/oauth-redirect.js +8 -0
- package/dist/oauth-redirect.test.d.ts +1 -0
- package/dist/oauth-redirect.test.js +39 -0
- package/dist/oauth-service.js +2 -2
- package/dist/routes-openapi.d.ts +101 -0
- package/dist/routes-openapi.js +21 -0
- package/dist/routes.d.ts +3 -1
- package/dist/routes.js +52 -4
- package/dist/runtime-contributor.test.js +36 -1
- package/dist/runtime-port.d.ts +36 -0
- package/dist/runtime-port.js +20 -0
- package/dist/voyant.js +6 -2
- package/openapi/admin/apps.json +6 -0
- package/package.json +12 -7
package/dist/routes-openapi.d.ts
CHANGED
|
@@ -89,6 +89,7 @@ export declare const authorizeAppOAuthRoute: {
|
|
|
89
89
|
release_id: z.ZodString;
|
|
90
90
|
redirect_uri: z.ZodString;
|
|
91
91
|
state: z.ZodString;
|
|
92
|
+
nonce: z.ZodOptional<z.ZodString>;
|
|
92
93
|
code_challenge: z.ZodString;
|
|
93
94
|
code_challenge_method: z.ZodLiteral<"S256">;
|
|
94
95
|
actor_id: z.ZodOptional<z.ZodString>;
|
|
@@ -382,6 +383,106 @@ export declare const installAppRoute: {
|
|
|
382
383
|
} & {
|
|
383
384
|
getRoutingPath(): "/install";
|
|
384
385
|
};
|
|
386
|
+
export declare const resolveMarketplaceInstallIntentRoute: {
|
|
387
|
+
method: "post";
|
|
388
|
+
path: "/marketplace/install-intents/resolve";
|
|
389
|
+
request: {
|
|
390
|
+
body: {
|
|
391
|
+
required: boolean;
|
|
392
|
+
content: {
|
|
393
|
+
"application/json": {
|
|
394
|
+
schema: z.ZodObject<{
|
|
395
|
+
intent: z.ZodString;
|
|
396
|
+
}, z.core.$strict>;
|
|
397
|
+
};
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
};
|
|
401
|
+
responses: {
|
|
402
|
+
201: {
|
|
403
|
+
description: string;
|
|
404
|
+
content: {
|
|
405
|
+
"application/json": {
|
|
406
|
+
schema: z.ZodObject<{
|
|
407
|
+
data: z.ZodObject<{
|
|
408
|
+
appId: z.ZodString;
|
|
409
|
+
releaseId: z.ZodString;
|
|
410
|
+
acquisitionId: z.ZodString;
|
|
411
|
+
created: z.ZodBoolean;
|
|
412
|
+
}, z.core.$strict>;
|
|
413
|
+
}, z.core.$strip>;
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
404: {
|
|
418
|
+
description: string;
|
|
419
|
+
content: {
|
|
420
|
+
"application/json": {
|
|
421
|
+
schema: z.ZodObject<{
|
|
422
|
+
error: z.ZodString;
|
|
423
|
+
}, z.core.$strip>;
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
501: {
|
|
428
|
+
description: string;
|
|
429
|
+
content: {
|
|
430
|
+
"application/json": {
|
|
431
|
+
schema: z.ZodObject<{
|
|
432
|
+
error: z.ZodString;
|
|
433
|
+
}, z.core.$strip>;
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
} & {
|
|
439
|
+
getRoutingPath(): "/marketplace/install-intents/resolve";
|
|
440
|
+
};
|
|
441
|
+
export declare const createMarketplaceSetupHandoffRoute: {
|
|
442
|
+
method: "post";
|
|
443
|
+
path: "/installations/{installationId}/setup-handoff";
|
|
444
|
+
request: {
|
|
445
|
+
params: z.ZodObject<{
|
|
446
|
+
installationId: z.ZodString;
|
|
447
|
+
}, z.core.$strip>;
|
|
448
|
+
};
|
|
449
|
+
responses: {
|
|
450
|
+
201: {
|
|
451
|
+
description: string;
|
|
452
|
+
content: {
|
|
453
|
+
"application/json": {
|
|
454
|
+
schema: z.ZodObject<{
|
|
455
|
+
data: z.ZodObject<{
|
|
456
|
+
redirectUrl: z.ZodString;
|
|
457
|
+
}, z.core.$strict>;
|
|
458
|
+
}, z.core.$strip>;
|
|
459
|
+
};
|
|
460
|
+
};
|
|
461
|
+
};
|
|
462
|
+
404: {
|
|
463
|
+
description: string;
|
|
464
|
+
content: {
|
|
465
|
+
"application/json": {
|
|
466
|
+
schema: z.ZodObject<{
|
|
467
|
+
error: z.ZodString;
|
|
468
|
+
}, z.core.$strip>;
|
|
469
|
+
};
|
|
470
|
+
};
|
|
471
|
+
};
|
|
472
|
+
501: {
|
|
473
|
+
description: string;
|
|
474
|
+
content: {
|
|
475
|
+
"application/json": {
|
|
476
|
+
schema: z.ZodObject<{
|
|
477
|
+
error: z.ZodString;
|
|
478
|
+
}, z.core.$strip>;
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
};
|
|
483
|
+
} & {
|
|
484
|
+
getRoutingPath(): "/installations/:installationId/setup-handoff";
|
|
485
|
+
};
|
|
385
486
|
export declare const listAppInstallationsRoute: {
|
|
386
487
|
method: "get";
|
|
387
488
|
path: "/installations";
|
package/dist/routes-openapi.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRoute, z } from "@hono/zod-openapi";
|
|
2
2
|
import { activateInstallationBodySchema, appCredentialRevocationSchema, appInstallationAuditQuerySchema, appInstallationListQuerySchema, appListQuerySchema, appOAuthAuthorizeQuerySchema, appOAuthTokenSchema, appSessionTokenExchangeSchema, appSessionTokenIssueSchema, appWebhookReplaySchema, createCustomAppRegistrationSchema, installAppSchema, lifecycleActionBodySchema, releaseManifestFetchSchema, releaseManifestUploadSchema, } from "./contracts.js";
|
|
3
|
+
import { marketplaceInstallIntentResultSchema, marketplaceSetupHandoffResultSchema, resolveMarketplaceInstallIntentSchema, } from "./marketplace-acquisition.js";
|
|
3
4
|
const appIdParamSchema = z.object({ appId: z.string().min(1) });
|
|
4
5
|
const installationIdParamSchema = z.object({ installationId: z.string().min(1) });
|
|
5
6
|
const errorSchema = z.object({ error: z.string() });
|
|
@@ -100,6 +101,26 @@ export const installAppRoute = createRoute({
|
|
|
100
101
|
request: { body: requiredJsonBody(installAppSchema) },
|
|
101
102
|
responses: { 201: jsonContent(dataEnvelopeSchema, "Installed app") },
|
|
102
103
|
});
|
|
104
|
+
export const resolveMarketplaceInstallIntentRoute = createRoute({
|
|
105
|
+
method: "post",
|
|
106
|
+
path: "/marketplace/install-intents/resolve",
|
|
107
|
+
request: { body: requiredJsonBody(resolveMarketplaceInstallIntentSchema) },
|
|
108
|
+
responses: {
|
|
109
|
+
201: jsonContent(marketplaceInstallIntentResultSchema, "Admitted Marketplace install intent"),
|
|
110
|
+
404: jsonContent(errorSchema, "Install intent unavailable"),
|
|
111
|
+
501: jsonContent(errorSchema, "Managed Marketplace is not configured"),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
export const createMarketplaceSetupHandoffRoute = createRoute({
|
|
115
|
+
method: "post",
|
|
116
|
+
path: "/installations/{installationId}/setup-handoff",
|
|
117
|
+
request: { params: installationIdParamSchema },
|
|
118
|
+
responses: {
|
|
119
|
+
201: jsonContent(marketplaceSetupHandoffResultSchema, "Created one-time app setup handoff"),
|
|
120
|
+
404: jsonContent(errorSchema, "Marketplace installation unavailable"),
|
|
121
|
+
501: jsonContent(errorSchema, "Managed Marketplace is not configured"),
|
|
122
|
+
},
|
|
123
|
+
});
|
|
103
124
|
export const listAppInstallationsRoute = createRoute({
|
|
104
125
|
method: "get",
|
|
105
126
|
path: "/installations",
|
package/dist/routes.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { EventBus } from "@voyant-travel/core/events";
|
|
|
3
3
|
import type { createCustomFieldsService } from "@voyant-travel/custom-fields";
|
|
4
4
|
import { type AccessCatalog } from "@voyant-travel/types/api-keys";
|
|
5
5
|
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
6
|
-
import type { ManagedAppInstallationAuthority } from "./runtime-port.js";
|
|
6
|
+
import type { ManagedAppInstallationAuthority, ManagedMarketplaceAcquisitionResolver } from "./runtime-port.js";
|
|
7
7
|
import { type AppsServiceOptions } from "./service.js";
|
|
8
8
|
type CustomFieldsService = ReturnType<typeof createCustomFieldsService>;
|
|
9
9
|
type Env = {
|
|
@@ -38,6 +38,8 @@ export interface AppsAdminRouteOptions extends AppsServiceOptions {
|
|
|
38
38
|
platformApiVersion?: string;
|
|
39
39
|
eventBus?: EventBus;
|
|
40
40
|
customFields?: CustomFieldsService;
|
|
41
|
+
/** Host-verified Marketplace acquisition and setup authority. */
|
|
42
|
+
managedMarketplace?: ManagedMarketplaceAcquisitionResolver;
|
|
41
43
|
}
|
|
42
44
|
export declare function createAppsAdminRoutes(options?: AppsAdminRouteOptions): OpenAPIHono<Env, {}, "/">;
|
|
43
45
|
export declare function resolveViewerRemoteAppScopes(scopes: readonly string[], catalog: AccessCatalog | undefined): string[];
|
package/dist/routes.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
2
|
import { openApiValidationHook, parseJsonBody, parseQuery, RequestValidationError, requireUserId, } from "@voyant-travel/hono";
|
|
3
3
|
import { hasApiKeyPermission, permissionStringsToPermissions, } from "@voyant-travel/types/api-keys";
|
|
4
|
+
import { eq } from "drizzle-orm";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
import { grantableRemoteAppScopes } from "./consent.js";
|
|
6
7
|
import { activateInstallationBodySchema, appCredentialRevocationSchema, appInstallationAuditQuerySchema, appInstallationListQuerySchema, appListQuerySchema, appOAuthAuthorizeQuerySchema, appOAuthTokenSchema, appSessionTokenExchangeSchema, appSessionTokenIssueSchema, appWebhookReplaySchema, createCustomAppRegistrationSchema, installAppSchema, lifecycleActionBodySchema, releaseManifestFetchSchema, releaseManifestUploadSchema, } from "./contracts.js";
|
|
7
8
|
import { listAppReleases, listInstallationAudit, listInstallationSummaries, loadInstallationDetail, } from "./installation-read-model.js";
|
|
8
9
|
import { createAppInstallationService } from "./installation-service.js";
|
|
10
|
+
import { createMarketplaceAcquisitionService, resolveMarketplaceInstallIntentSchema, } from "./marketplace-acquisition.js";
|
|
11
|
+
import { buildAppOAuthCallbackUrl } from "./oauth-redirect.js";
|
|
9
12
|
import { createAppOAuthService } from "./oauth-service.js";
|
|
10
|
-
import { activateAppInstallationRoute, authorizeAppOAuthRoute, createAppReleaseRoute, createCustomAppRoute, exchangeAppSessionTokenRoute, fetchAppReleaseRoute, getAppInstallationRoute, getAppRoute, installAppRoute, issueAppOAuthTokenRoute, issueAppSessionTokenRoute, listAppInstallationAuditRoute, listAppInstallationsRoute, listAppReleasesRoute, listAppsRoute, listAppWebhooksRoute, pauseAppInstallationRoute, previewAppInstallationPurgeRoute, replayAppWebhookRoute, resumeAppInstallationRoute, revokeAppInstallationCredentialsRoute, uninstallAppInstallationRoute, } from "./routes-openapi.js";
|
|
13
|
+
import { activateAppInstallationRoute, authorizeAppOAuthRoute, createAppReleaseRoute, createCustomAppRoute, createMarketplaceSetupHandoffRoute, exchangeAppSessionTokenRoute, fetchAppReleaseRoute, getAppInstallationRoute, getAppRoute, installAppRoute, issueAppOAuthTokenRoute, issueAppSessionTokenRoute, listAppInstallationAuditRoute, listAppInstallationsRoute, listAppReleasesRoute, listAppsRoute, listAppWebhooksRoute, pauseAppInstallationRoute, previewAppInstallationPurgeRoute, replayAppWebhookRoute, resolveMarketplaceInstallIntentRoute, resumeAppInstallationRoute, revokeAppInstallationCredentialsRoute, uninstallAppInstallationRoute, } from "./routes-openapi.js";
|
|
14
|
+
import { apps } from "./schema.js";
|
|
11
15
|
import { createAppsService } from "./service.js";
|
|
12
16
|
import { createAppSessionTokenService } from "./session-token-service.js";
|
|
13
17
|
import { listAppWebhookHealth, replayAppWebhookDelivery } from "./webhook-delivery.js";
|
|
@@ -16,6 +20,13 @@ const installationIdParamSchema = z.object({ installationId: z.string().min(1) }
|
|
|
16
20
|
export function createAppsAdminRoutes(options = {}) {
|
|
17
21
|
const routes = new OpenAPIHono({ defaultHook: openApiValidationHook });
|
|
18
22
|
const service = createAppsService(options);
|
|
23
|
+
const marketplace = options.managedMarketplace
|
|
24
|
+
? createMarketplaceAcquisitionService({
|
|
25
|
+
eventCatalog: options.eventCatalog,
|
|
26
|
+
resolveAcquisitionIntent: options.managedMarketplace.resolveAcquisitionIntent,
|
|
27
|
+
createSetupHandoff: options.managedMarketplace.createSetupHandoff,
|
|
28
|
+
})
|
|
29
|
+
: null;
|
|
19
30
|
const installations = createAppInstallationService({
|
|
20
31
|
deploymentId: options.oauth?.deploymentId ?? options.deploymentId,
|
|
21
32
|
managedInstallation: options.oauth?.managedInstallation,
|
|
@@ -62,9 +73,12 @@ export function createAppsAdminRoutes(options = {}) {
|
|
|
62
73
|
operatorGrantedScopes: resolveOperatorGrantableRemoteAppScopes(c.get("scopes") ?? [], oauthAccessCatalog),
|
|
63
74
|
grantedOptionalScopes: splitScopes(body.optional_scopes),
|
|
64
75
|
});
|
|
65
|
-
const redirectUrl =
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
const redirectUrl = buildAppOAuthCallbackUrl({
|
|
77
|
+
redirectUri: result.redirectUri,
|
|
78
|
+
code: result.code,
|
|
79
|
+
state: result.state,
|
|
80
|
+
...(body.nonce ? { nonce: body.nonce } : {}),
|
|
81
|
+
});
|
|
68
82
|
return c.json({ data: { redirectUrl: redirectUrl.toString(), state: result.state } }, 200);
|
|
69
83
|
});
|
|
70
84
|
routes.openapi(issueAppOAuthTokenRoute, async (c) => {
|
|
@@ -144,6 +158,24 @@ export function createAppsAdminRoutes(options = {}) {
|
|
|
144
158
|
});
|
|
145
159
|
return c.json({ data: result }, 201);
|
|
146
160
|
});
|
|
161
|
+
routes.openapi(resolveMarketplaceInstallIntentRoute, async (c) => {
|
|
162
|
+
if (!marketplace)
|
|
163
|
+
return c.json({ error: "Managed Marketplace is not configured" }, 501);
|
|
164
|
+
const body = await parseJsonBody(c, resolveMarketplaceInstallIntentSchema);
|
|
165
|
+
const data = await marketplace.resolveAndAcquire(c.get("db"), {
|
|
166
|
+
intent: body.intent,
|
|
167
|
+
actorId: requireUserId(c),
|
|
168
|
+
});
|
|
169
|
+
return c.json({ data }, 201);
|
|
170
|
+
});
|
|
171
|
+
routes.openapi(createMarketplaceSetupHandoffRoute, async (c) => {
|
|
172
|
+
if (!marketplace)
|
|
173
|
+
return c.json({ error: "Managed Marketplace is not configured" }, 501);
|
|
174
|
+
requireUserId(c);
|
|
175
|
+
const { installationId } = parseInstallationParams(c.req.param());
|
|
176
|
+
const data = await marketplace.createSetupHandoff(c.get("db"), installationId);
|
|
177
|
+
return c.json({ data }, 201);
|
|
178
|
+
});
|
|
147
179
|
routes.openapi(listAppInstallationsRoute, async (c) => {
|
|
148
180
|
const query = parseQuery(c, appInstallationListQuerySchema);
|
|
149
181
|
return c.json(await listInstallationSummaries(c.get("db"), query), 200);
|
|
@@ -185,6 +217,22 @@ export function createAppsAdminRoutes(options = {}) {
|
|
|
185
217
|
installationId,
|
|
186
218
|
actorId: body.actorId,
|
|
187
219
|
});
|
|
220
|
+
if (options.managedMarketplace) {
|
|
221
|
+
const [registration] = await c
|
|
222
|
+
.get("db")
|
|
223
|
+
.select({ distribution: apps.distribution })
|
|
224
|
+
.from(apps)
|
|
225
|
+
.where(eq(apps.id, result.installation.appId))
|
|
226
|
+
.limit(1);
|
|
227
|
+
if (registration?.distribution === "marketplace") {
|
|
228
|
+
await options.managedMarketplace.notifyInstallationLifecycle({
|
|
229
|
+
event: "uninstalled",
|
|
230
|
+
installationId: result.installation.id,
|
|
231
|
+
appId: result.installation.appId,
|
|
232
|
+
releaseId: result.installation.releaseId,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
188
236
|
return c.json({ data: result }, 200);
|
|
189
237
|
});
|
|
190
238
|
routes.openapi(activateAppInstallationRoute, async (c) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { createAppsRuntimePortContribution } from "./runtime-contributor.js";
|
|
3
|
-
import { appsManagedAuthRuntimePort } from "./runtime-port.js";
|
|
3
|
+
import { appsManagedAuthRuntimePort, appsManagedMarketplaceRuntimePort } from "./runtime-port.js";
|
|
4
4
|
function host(values) {
|
|
5
5
|
return {
|
|
6
6
|
hasRuntimePort: () => false,
|
|
@@ -52,4 +52,39 @@ describe("createAppsRuntimePortContribution", () => {
|
|
|
52
52
|
releaseId: "release_2",
|
|
53
53
|
})).resolves.toEqual({ contractGeneration: 9 });
|
|
54
54
|
});
|
|
55
|
+
it("requires both opaque acquisition resolution and trusted setup handoff", () => {
|
|
56
|
+
expect(() => appsManagedMarketplaceRuntimePort.test({
|
|
57
|
+
deploymentId: "deployment-1",
|
|
58
|
+
acquisitionResolver: {
|
|
59
|
+
resolveAcquisitionIntent: async () => null,
|
|
60
|
+
createSetupHandoff: async () => ({
|
|
61
|
+
redirectUrl: "https://app.example.com/setup?code=opaque",
|
|
62
|
+
}),
|
|
63
|
+
notifyInstallationLifecycle: async () => undefined,
|
|
64
|
+
},
|
|
65
|
+
})).not.toThrow();
|
|
66
|
+
expect(() => appsManagedMarketplaceRuntimePort.test({
|
|
67
|
+
deploymentId: "deployment-1",
|
|
68
|
+
acquisitionResolver: { resolveAcquisitionIntent: async () => null },
|
|
69
|
+
})).toThrow(/createSetupHandoff/);
|
|
70
|
+
expect(() => appsManagedMarketplaceRuntimePort.test({
|
|
71
|
+
deploymentId: "deployment-1",
|
|
72
|
+
acquisitionResolver: {
|
|
73
|
+
resolveAcquisitionIntent: async () => null,
|
|
74
|
+
createSetupHandoff: async () => ({
|
|
75
|
+
redirectUrl: "https://app.example.com/setup?code=opaque",
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
})).toThrow(/notifyInstallationLifecycle/);
|
|
79
|
+
expect(() => appsManagedMarketplaceRuntimePort.test({
|
|
80
|
+
deploymentId: "",
|
|
81
|
+
acquisitionResolver: {
|
|
82
|
+
resolveAcquisitionIntent: async () => null,
|
|
83
|
+
createSetupHandoff: async () => ({
|
|
84
|
+
redirectUrl: "https://app.example.com/setup?code=opaque",
|
|
85
|
+
}),
|
|
86
|
+
notifyInstallationLifecycle: async () => undefined,
|
|
87
|
+
},
|
|
88
|
+
})).toThrow(/deploymentId/);
|
|
89
|
+
});
|
|
55
90
|
});
|
package/dist/runtime-port.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HostVerifiedMarketplaceAcquisition } from "./marketplace-acquisition.js";
|
|
1
2
|
/** Persisted host contract for one managed app installation. */
|
|
2
3
|
export interface ManagedAppInstallationBinding {
|
|
3
4
|
workloadEnvironmentId: string;
|
|
@@ -27,3 +28,38 @@ export interface AppsManagedAuthRuntime {
|
|
|
27
28
|
sessionTokenTtlSeconds?: number;
|
|
28
29
|
}
|
|
29
30
|
export declare const appsManagedAuthRuntimePort: import("@voyant-travel/core/project").VoyantPort<AppsManagedAuthRuntime>;
|
|
31
|
+
export interface ManagedMarketplaceAcquisitionResolver {
|
|
32
|
+
/**
|
|
33
|
+
* Resolve an opaque, single-purpose install intent through host authority.
|
|
34
|
+
* The public runtime never accepts catalog coordinates, artifact URLs, or
|
|
35
|
+
* publisher assertions from the browser.
|
|
36
|
+
*/
|
|
37
|
+
resolveAcquisitionIntent(input: {
|
|
38
|
+
intent: string;
|
|
39
|
+
}): Promise<HostVerifiedMarketplaceAcquisition | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Mint and deliver a short-lived, host-signed setup assertion. The browser
|
|
42
|
+
* receives only the resulting one-time redirect and never chooses OAuth
|
|
43
|
+
* coordinates or assertion claims.
|
|
44
|
+
*/
|
|
45
|
+
createSetupHandoff(input: {
|
|
46
|
+
installationId: string;
|
|
47
|
+
appId: string;
|
|
48
|
+
releaseId: string;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
redirectUrl: string;
|
|
51
|
+
}>;
|
|
52
|
+
/** Deliver an idempotent host-signed lifecycle assertion to the publisher. */
|
|
53
|
+
notifyInstallationLifecycle(input: {
|
|
54
|
+
event: "uninstalled";
|
|
55
|
+
installationId: string;
|
|
56
|
+
appId: string;
|
|
57
|
+
releaseId: string;
|
|
58
|
+
}): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
export interface AppsManagedMarketplaceRuntime {
|
|
61
|
+
/** Stable host deployment identity used for deployment-local installation rows. */
|
|
62
|
+
deploymentId: string;
|
|
63
|
+
acquisitionResolver: ManagedMarketplaceAcquisitionResolver;
|
|
64
|
+
}
|
|
65
|
+
export declare const appsManagedMarketplaceRuntimePort: import("@voyant-travel/core/project").VoyantPort<AppsManagedMarketplaceRuntime>;
|
package/dist/runtime-port.js
CHANGED
|
@@ -26,3 +26,23 @@ export const appsManagedAuthRuntimePort = definePort({
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
});
|
|
29
|
+
export const appsManagedMarketplaceRuntimePort = definePort({
|
|
30
|
+
id: "apps.managed-marketplace",
|
|
31
|
+
test(runtime) {
|
|
32
|
+
if (!runtime || typeof runtime !== "object") {
|
|
33
|
+
throw new TypeError("apps.managed-marketplace must be an object.");
|
|
34
|
+
}
|
|
35
|
+
if (typeof runtime.deploymentId !== "string" || runtime.deploymentId.trim().length === 0) {
|
|
36
|
+
throw new TypeError("apps.managed-marketplace deploymentId must be a non-empty string.");
|
|
37
|
+
}
|
|
38
|
+
if (typeof runtime.acquisitionResolver?.resolveAcquisitionIntent !== "function") {
|
|
39
|
+
throw new TypeError("apps.managed-marketplace acquisitionResolver.resolveAcquisitionIntent must be a function.");
|
|
40
|
+
}
|
|
41
|
+
if (typeof runtime.acquisitionResolver.createSetupHandoff !== "function") {
|
|
42
|
+
throw new TypeError("apps.managed-marketplace acquisitionResolver.createSetupHandoff must be a function.");
|
|
43
|
+
}
|
|
44
|
+
if (typeof runtime.acquisitionResolver.notifyInstallationLifecycle !== "function") {
|
|
45
|
+
throw new TypeError("apps.managed-marketplace acquisitionResolver.notifyInstallationLifecycle must be a function.");
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
package/dist/voyant.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineModule, providePort, requirePort } from "@voyant-travel/core/project";
|
|
2
2
|
import { customFieldValueLifecycleRuntimePort, customFieldValueOperationsRuntimePort, } from "@voyant-travel/core/runtime-port";
|
|
3
3
|
import { financeAppApiRuntimePort } from "@voyant-travel/finance-contracts/runtime-port";
|
|
4
|
-
import { appsManagedAuthRuntimePort } from "./runtime-port.js";
|
|
4
|
+
import { appsManagedAuthRuntimePort, appsManagedMarketplaceRuntimePort } from "./runtime-port.js";
|
|
5
5
|
const appsAdminRuntime = {
|
|
6
6
|
entry: "@voyant-travel/apps-react/admin",
|
|
7
7
|
export: "createSelectedAppsAdminExtension",
|
|
@@ -31,9 +31,13 @@ export const appsVoyantModule = defineModule({
|
|
|
31
31
|
}),
|
|
32
32
|
requirePort(financeAppApiRuntimePort, { optional: true }),
|
|
33
33
|
requirePort(appsManagedAuthRuntimePort, { optional: true }),
|
|
34
|
+
requirePort(appsManagedMarketplaceRuntimePort, { optional: true }),
|
|
34
35
|
],
|
|
35
36
|
provides: {
|
|
36
|
-
ports: [
|
|
37
|
+
ports: [
|
|
38
|
+
providePort(appsManagedAuthRuntimePort),
|
|
39
|
+
providePort(appsManagedMarketplaceRuntimePort),
|
|
40
|
+
],
|
|
37
41
|
},
|
|
38
42
|
api: [
|
|
39
43
|
{
|
package/openapi/admin/apps.json
CHANGED
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"/v1/admin/apps/install": {
|
|
26
26
|
"post": { "summary": "Install an app release" }
|
|
27
27
|
},
|
|
28
|
+
"/v1/admin/apps/marketplace/install-intents/resolve": {
|
|
29
|
+
"post": { "summary": "Resolve and admit an opaque Marketplace install intent" }
|
|
30
|
+
},
|
|
28
31
|
"/v1/admin/apps/installations": {
|
|
29
32
|
"get": { "summary": "List app installations" }
|
|
30
33
|
},
|
|
@@ -52,6 +55,9 @@
|
|
|
52
55
|
"/v1/admin/apps/installations/{installationId}/session-token": {
|
|
53
56
|
"post": { "summary": "Issue an app extension session token" }
|
|
54
57
|
},
|
|
58
|
+
"/v1/admin/apps/installations/{installationId}/setup-handoff": {
|
|
59
|
+
"post": { "summary": "Create a one-time Marketplace app setup handoff" }
|
|
60
|
+
},
|
|
55
61
|
"/v1/admin/apps/installations/{installationId}/webhooks": {
|
|
56
62
|
"get": { "summary": "List app webhook delivery health" }
|
|
57
63
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/apps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,6 +64,11 @@
|
|
|
64
64
|
"import": "./dist/locale-resolution.js",
|
|
65
65
|
"default": "./dist/locale-resolution.js"
|
|
66
66
|
},
|
|
67
|
+
"./marketplace-acquisition": {
|
|
68
|
+
"types": "./dist/marketplace-acquisition.d.ts",
|
|
69
|
+
"import": "./dist/marketplace-acquisition.js",
|
|
70
|
+
"default": "./dist/marketplace-acquisition.js"
|
|
71
|
+
},
|
|
67
72
|
"./installation-service": {
|
|
68
73
|
"types": "./dist/installation-service.d.ts",
|
|
69
74
|
"import": "./dist/installation-service.js",
|
|
@@ -126,15 +131,15 @@
|
|
|
126
131
|
"drizzle-orm": "^0.45.2",
|
|
127
132
|
"hono": "^4.12.27",
|
|
128
133
|
"zod": "^4.4.3",
|
|
129
|
-
"@voyant-travel/admin-extension-sdk": "^0.2.0",
|
|
130
|
-
"@voyant-travel/core": "^0.127.1",
|
|
131
134
|
"@voyant-travel/admin": "^0.127.0",
|
|
132
|
-
"@voyant-travel/
|
|
135
|
+
"@voyant-travel/admin-extension-sdk": "^0.2.0",
|
|
136
|
+
"@voyant-travel/core": "^0.128.0",
|
|
137
|
+
"@voyant-travel/custom-fields": "^0.2.5",
|
|
133
138
|
"@voyant-travel/finance-contracts": "^0.107.0",
|
|
134
|
-
"@voyant-travel/db": "^0.114.
|
|
135
|
-
"@voyant-travel/hono": "^0.
|
|
139
|
+
"@voyant-travel/db": "^0.114.14",
|
|
140
|
+
"@voyant-travel/hono": "^0.130.0",
|
|
136
141
|
"@voyant-travel/types": "^0.109.4",
|
|
137
|
-
"@voyant-travel/webhook-delivery": "^0.4.
|
|
142
|
+
"@voyant-travel/webhook-delivery": "^0.4.3"
|
|
138
143
|
},
|
|
139
144
|
"devDependencies": {
|
|
140
145
|
"@types/node": "^25.5.2",
|