@appport/server 1.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.
@@ -0,0 +1,91 @@
1
+ import { type AppPortManifest, type AppResponse, type ClientEnvelope, type DiscoveryDocument, type Principal, type ServerEnvelope, type Session } from "@appport/protocol";
2
+ import { type UiContribution, type UiDiscoveryDocument } from "@appport/protocol";
3
+ import { type AppPortApplication } from "@appport/core/server-internal";
4
+ import { AppPortConnection, type SendEnvelope } from "./connection.js";
5
+ /** What a transport knows about a caller before any AppPort envelope is read. */
6
+ export interface AuthenticationRequest {
7
+ transport: string;
8
+ /** Session identifier supplied by the transport (header, IPC attribute, …). */
9
+ sessionId?: string;
10
+ /** Raw transport credentials. Opaque to AppPort; interpreted by the hook. */
11
+ headers?: Readonly<Record<string, string | undefined>>;
12
+ origin?: string;
13
+ /** Transport-specific caller detail (an Electron `WebContents` id, …). */
14
+ peer?: unknown;
15
+ }
16
+ export interface Identity {
17
+ session?: Session;
18
+ principal?: Principal;
19
+ capabilities?: readonly string[];
20
+ tenant?: string;
21
+ application?: string;
22
+ environment?: string;
23
+ }
24
+ /**
25
+ * Resolves an identity from transport-supplied credentials.
26
+ *
27
+ * AppPort deliberately does not authenticate: it represents the resulting
28
+ * identity (§35). Returning `{}` means anonymous — which is not the same as
29
+ * trusted, on any transport (§37, §38).
30
+ */
31
+ export type Authenticate = (request: AuthenticationRequest) => Identity | undefined | Promise<Identity | undefined>;
32
+ export interface ServerOptions {
33
+ application: AppPortApplication;
34
+ authenticate?: Authenticate;
35
+ maxEnvelopeBytes?: number;
36
+ /** Endpoint paths advertised through discovery (§39, §40). */
37
+ endpoints?: {
38
+ request?: string;
39
+ websocket?: string;
40
+ manifest?: string;
41
+ };
42
+ /** Optional descriptive UI contribution for this product. */
43
+ ui?: UiContribution;
44
+ }
45
+ /**
46
+ * The server-side protocol runtime.
47
+ *
48
+ * It turns envelopes into dispatches and results back into envelopes, and owns
49
+ * discovery. It is transport-agnostic: HTTP, WebSocket and IPC bindings are
50
+ * thin adapters over this class.
51
+ */
52
+ export declare class AppPortServer {
53
+ #private;
54
+ readonly application: AppPortApplication;
55
+ readonly endpoints: {
56
+ request: string;
57
+ websocket: string;
58
+ manifest: string;
59
+ };
60
+ constructor(options: ServerOptions);
61
+ get connectionCount(): number;
62
+ manifest(): AppPortManifest;
63
+ /** The `.well-known` discovery document (§39). */
64
+ discovery(): DiscoveryDocument;
65
+ uiDiscovery(identity: Identity): UiDiscoveryDocument | undefined;
66
+ identify(request: AuthenticationRequest): Promise<Identity>;
67
+ /** Opens a duplex connection (WebSocket, IPC, in-process). */
68
+ createConnection(options: {
69
+ transport: string;
70
+ send: SendEnvelope;
71
+ identity?: Identity;
72
+ allowedCapabilities?: ReadonlySet<string>;
73
+ }): AppPortConnection;
74
+ releaseConnection(connection: AppPortConnection): void;
75
+ /**
76
+ * Handles a single request envelope without a persistent connection — the
77
+ * shape plain HTTP needs.
78
+ */
79
+ handleUnary(value: unknown, context: {
80
+ identity?: Identity;
81
+ transport: string;
82
+ allowedCapabilities?: ReadonlySet<string>;
83
+ }): Promise<AppResponse>;
84
+ /** Decodes a text frame into a validated client envelope. */
85
+ parseText(raw: string): ClientEnvelope;
86
+ errorEnvelope(requestId: string | undefined, error: unknown, traceId?: string): ServerEnvelope;
87
+ /** Closes every open connection. */
88
+ close(): Promise<void>;
89
+ }
90
+ export declare function createServer(options: ServerOptions): AppPortServer;
91
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js ADDED
@@ -0,0 +1,127 @@
1
+ import { createErrorResponse, DEFAULT_HTTP_ENDPOINT, DEFAULT_MANIFEST_PATH, DEFAULT_WS_ENDPOINT, decodeEnvelopeText, errors, parseClientEnvelope, peekRequestId, peekTraceId, PROTOCOL_ID } from "@appport/protocol";
2
+ import { filterUiContribution, validateUiContribution } from "@appport/protocol";
3
+ import { toWireError } from "@appport/core/server-internal";
4
+ import { AppPortConnection } from "./connection.js";
5
+ /**
6
+ * The server-side protocol runtime.
7
+ *
8
+ * It turns envelopes into dispatches and results back into envelopes, and owns
9
+ * discovery. It is transport-agnostic: HTTP, WebSocket and IPC bindings are
10
+ * thin adapters over this class.
11
+ */
12
+ export class AppPortServer {
13
+ application;
14
+ #authenticate;
15
+ #maxEnvelopeBytes;
16
+ endpoints;
17
+ #ui;
18
+ #connections = new Set();
19
+ constructor(options) {
20
+ this.application = options.application;
21
+ this.#authenticate = options.authenticate;
22
+ this.#maxEnvelopeBytes = options.maxEnvelopeBytes;
23
+ this.endpoints = {
24
+ request: options.endpoints?.request ?? DEFAULT_HTTP_ENDPOINT,
25
+ websocket: options.endpoints?.websocket ?? DEFAULT_WS_ENDPOINT,
26
+ manifest: options.endpoints?.manifest ?? DEFAULT_MANIFEST_PATH
27
+ };
28
+ this.#ui = options.ui ? validateUiContribution(options.ui) : undefined;
29
+ }
30
+ get connectionCount() {
31
+ return this.#connections.size;
32
+ }
33
+ manifest() {
34
+ return this.application.manifest();
35
+ }
36
+ /** The `.well-known` discovery document (§39). */
37
+ discovery() {
38
+ const manifest = this.manifest();
39
+ return {
40
+ protocol: PROTOCOL_ID,
41
+ manifest: this.endpoints.manifest,
42
+ endpoint: this.endpoints.request,
43
+ application: {
44
+ id: manifest.application.id,
45
+ name: manifest.application.name,
46
+ version: manifest.application.version
47
+ },
48
+ transports: manifest.transports
49
+ };
50
+ }
51
+ uiDiscovery(identity) {
52
+ if (!this.#ui)
53
+ return undefined;
54
+ const requires = new Set(this.#ui.composition.requires);
55
+ const contextAvailable = (!requires.has("identity") || Boolean(identity.principal)) &&
56
+ (!requires.has("tenant") || Boolean(identity.tenant)) &&
57
+ (!requires.has("application") || Boolean(identity.application)) &&
58
+ (!requires.has("environment") || Boolean(identity.environment));
59
+ return filterUiContribution(this.#ui, contextAvailable ? identity.capabilities ?? identity.session?.permissions ?? [] : []);
60
+ }
61
+ async identify(request) {
62
+ if (!this.#authenticate)
63
+ return {};
64
+ return (await this.#authenticate(request)) ?? {};
65
+ }
66
+ /** Opens a duplex connection (WebSocket, IPC, in-process). */
67
+ createConnection(options) {
68
+ const connection = new AppPortConnection({
69
+ application: this.application,
70
+ transport: options.transport,
71
+ send: options.send,
72
+ ...(options.identity?.session ? { session: options.identity.session } : {}),
73
+ ...(options.identity?.principal ? { principal: options.identity.principal } : {}),
74
+ ...(options.allowedCapabilities ? { allowedCapabilities: options.allowedCapabilities } : {}),
75
+ ...(this.#maxEnvelopeBytes !== undefined ? { maxEnvelopeBytes: this.#maxEnvelopeBytes } : {})
76
+ });
77
+ this.#connections.add(connection);
78
+ return connection;
79
+ }
80
+ releaseConnection(connection) {
81
+ connection.close();
82
+ this.#connections.delete(connection);
83
+ }
84
+ /**
85
+ * Handles a single request envelope without a persistent connection — the
86
+ * shape plain HTTP needs.
87
+ */
88
+ async handleUnary(value, context) {
89
+ const requestId = peekRequestId(value);
90
+ const traceId = peekTraceId(value);
91
+ try {
92
+ const envelope = parseClientEnvelope(value);
93
+ if (envelope.type !== "request") {
94
+ throw errors.invalidRequest(`Envelope type "${envelope.type}" requires a duplex transport`);
95
+ }
96
+ if (context.allowedCapabilities && envelope.capability.name !== "appport.manifest" && envelope.capability.name !== "appport.ping" && !context.allowedCapabilities.has(envelope.capability.name)) {
97
+ throw errors.forbidden(`${envelope.capability.name} is not exposed to this surface`);
98
+ }
99
+ return await this.application.handleRequest(envelope, {
100
+ ...(context.identity?.session ? { session: context.identity.session } : {}),
101
+ ...(context.identity?.principal ? { principal: context.identity.principal } : {}),
102
+ transport: context.transport
103
+ });
104
+ }
105
+ catch (error) {
106
+ return createErrorResponse(requestId ?? "req_unknown", toWireError(error, this.application.mode), traceId ? { traceId } : {});
107
+ }
108
+ }
109
+ /** Decodes a text frame into a validated client envelope. */
110
+ parseText(raw) {
111
+ return parseClientEnvelope(decodeEnvelopeText(raw, this.#maxEnvelopeBytes ? { maxBytes: this.#maxEnvelopeBytes } : {}));
112
+ }
113
+ errorEnvelope(requestId, error, traceId) {
114
+ return createErrorResponse(requestId ?? "req_unknown", toWireError(error, this.application.mode), traceId ? { traceId } : {});
115
+ }
116
+ /** Closes every open connection. */
117
+ async close() {
118
+ for (const connection of this.#connections)
119
+ connection.close();
120
+ this.#connections.clear();
121
+ await this.application.close();
122
+ }
123
+ }
124
+ export function createServer(options) {
125
+ return new AppPortServer(options);
126
+ }
127
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { Duplex } from "node:stream";
2
+ import type { IncomingMessage } from "node:http";
3
+ export declare const DEFAULT_MAX_MESSAGE_BYTES: number;
4
+ export interface WebSocketPeerOptions {
5
+ maxMessageBytes?: number;
6
+ }
7
+ export type CloseListener = (code: number, reason: string) => void;
8
+ /** True when an HTTP request is a WebSocket upgrade. */
9
+ export declare function isWebSocketUpgrade(request: IncomingMessage): boolean;
10
+ export declare function acceptKey(key: string): string;
11
+ /** One accepted WebSocket connection. */
12
+ export declare class WebSocketPeer {
13
+ #private;
14
+ onMessage: ((data: string) => void) | undefined;
15
+ onClose: CloseListener | undefined;
16
+ onError: ((error: Error) => void) | undefined;
17
+ private constructor();
18
+ get closed(): boolean;
19
+ /** Completes the handshake and returns the peer, or null when it is not one. */
20
+ static accept(request: IncomingMessage, socket: Duplex, head: Buffer | undefined, options?: WebSocketPeerOptions): WebSocketPeer | null;
21
+ send(text: string): void;
22
+ ping(): void;
23
+ close(code?: number, reason?: string): void;
24
+ }
25
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAqBjD,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEnE,wDAAwD;AACxD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAGpE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,yCAAyC;AACzC,qBAAa,aAAa;;IAQxB,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAChD,OAAO,EAAE,aAAa,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAE9C,OAAO;IAYP,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,gFAAgF;IAChF,MAAM,CAAC,MAAM,CACX,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,GAAE,oBAAyB,GACjC,aAAa,GAAG,IAAI;IAsBvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,IAAI,IAAI;IAKZ,KAAK,CAAC,IAAI,SAAO,EAAE,MAAM,SAAK,GAAG,IAAI;CAqEtC"}
@@ -0,0 +1,221 @@
1
+ import { createHash } from "node:crypto";
2
+ /**
3
+ * A dependency-free RFC 6455 server endpoint.
4
+ *
5
+ * AppPort's WebSocket binding (§27) treats the socket as a pure carrier: every
6
+ * message is exactly one AppPort envelope. Implementing the framing here keeps
7
+ * `@appport/server` free of runtime dependencies and keeps the binding honest —
8
+ * nothing about the application semantics lives in the transport.
9
+ */
10
+ const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
11
+ const OPCODE = {
12
+ continuation: 0x0,
13
+ text: 0x1,
14
+ binary: 0x2,
15
+ close: 0x8,
16
+ ping: 0x9,
17
+ pong: 0xa
18
+ };
19
+ export const DEFAULT_MAX_MESSAGE_BYTES = 4 * 1024 * 1024;
20
+ /** True when an HTTP request is a WebSocket upgrade. */
21
+ export function isWebSocketUpgrade(request) {
22
+ const upgrade = request.headers["upgrade"];
23
+ return typeof upgrade === "string" && upgrade.toLowerCase() === "websocket";
24
+ }
25
+ export function acceptKey(key) {
26
+ return createHash("sha1").update(key + GUID).digest("base64");
27
+ }
28
+ /** One accepted WebSocket connection. */
29
+ export class WebSocketPeer {
30
+ #socket;
31
+ #maxMessageBytes;
32
+ #buffer = Buffer.alloc(0);
33
+ #fragments = [];
34
+ #fragmentOpcode = 0;
35
+ #closed = false;
36
+ onMessage;
37
+ onClose;
38
+ onError;
39
+ constructor(socket, options) {
40
+ this.#socket = socket;
41
+ this.#maxMessageBytes = options.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES;
42
+ socket.on("data", (chunk) => this.#ingest(chunk));
43
+ socket.on("error", (error) => {
44
+ this.onError?.(error);
45
+ this.#finish(1006, "socket error");
46
+ });
47
+ socket.on("close", () => this.#finish(1006, "socket closed"));
48
+ }
49
+ get closed() {
50
+ return this.#closed;
51
+ }
52
+ /** Completes the handshake and returns the peer, or null when it is not one. */
53
+ static accept(request, socket, head, options = {}) {
54
+ const key = request.headers["sec-websocket-key"];
55
+ const version = request.headers["sec-websocket-version"];
56
+ if (!isWebSocketUpgrade(request) || typeof key !== "string" || version !== "13") {
57
+ socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
58
+ return null;
59
+ }
60
+ socket.write([
61
+ "HTTP/1.1 101 Switching Protocols",
62
+ "Upgrade: websocket",
63
+ "Connection: Upgrade",
64
+ `Sec-WebSocket-Accept: ${acceptKey(key)}`,
65
+ "\r\n"
66
+ ].join("\r\n"));
67
+ socket.setNoDelay?.(true);
68
+ const peer = new WebSocketPeer(socket, options);
69
+ if (head?.length)
70
+ peer.#ingest(head);
71
+ return peer;
72
+ }
73
+ send(text) {
74
+ if (this.#closed)
75
+ return;
76
+ this.#socket.write(encodeFrame(OPCODE.text, Buffer.from(text, "utf8")));
77
+ }
78
+ ping() {
79
+ if (this.#closed)
80
+ return;
81
+ this.#socket.write(encodeFrame(OPCODE.ping, Buffer.alloc(0)));
82
+ }
83
+ close(code = 1000, reason = "") {
84
+ if (this.#closed)
85
+ return;
86
+ const payload = Buffer.alloc(2 + Buffer.byteLength(reason));
87
+ payload.writeUInt16BE(code, 0);
88
+ payload.write(reason, 2);
89
+ try {
90
+ this.#socket.write(encodeFrame(OPCODE.close, payload));
91
+ }
92
+ catch {
93
+ // The socket may already be gone; the close listener still fires.
94
+ }
95
+ this.#socket.end();
96
+ this.#finish(code, reason);
97
+ }
98
+ #finish(code, reason) {
99
+ if (this.#closed)
100
+ return;
101
+ this.#closed = true;
102
+ this.onClose?.(code, reason);
103
+ }
104
+ #ingest(chunk) {
105
+ this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
106
+ for (;;) {
107
+ const frame = decodeFrame(this.#buffer);
108
+ if (!frame)
109
+ return;
110
+ this.#buffer = this.#buffer.subarray(frame.consumed);
111
+ this.#dispatch(frame);
112
+ if (this.#closed)
113
+ return;
114
+ }
115
+ }
116
+ #dispatch(frame) {
117
+ switch (frame.opcode) {
118
+ case OPCODE.ping:
119
+ this.#socket.write(encodeFrame(OPCODE.pong, frame.payload));
120
+ return;
121
+ case OPCODE.pong:
122
+ return;
123
+ case OPCODE.close: {
124
+ const code = frame.payload.length >= 2 ? frame.payload.readUInt16BE(0) : 1005;
125
+ this.close(code === 1005 ? 1000 : code);
126
+ return;
127
+ }
128
+ case OPCODE.binary:
129
+ // AppPort v1 is UTF-8 JSON on the wire (§50); binary uses blob refs (§51).
130
+ this.close(1003, "binary frames are not accepted");
131
+ return;
132
+ case OPCODE.text:
133
+ case OPCODE.continuation: {
134
+ if (frame.opcode === OPCODE.text) {
135
+ this.#fragments = [];
136
+ this.#fragmentOpcode = OPCODE.text;
137
+ }
138
+ this.#fragments.push(frame.payload);
139
+ const size = this.#fragments.reduce((total, part) => total + part.length, 0);
140
+ if (size > this.#maxMessageBytes) {
141
+ this.close(1009, "message too large");
142
+ return;
143
+ }
144
+ if (!frame.fin)
145
+ return;
146
+ const message = Buffer.concat(this.#fragments).toString("utf8");
147
+ this.#fragments = [];
148
+ if (this.#fragmentOpcode === OPCODE.text)
149
+ this.onMessage?.(message);
150
+ return;
151
+ }
152
+ default:
153
+ this.close(1002, "unsupported opcode");
154
+ }
155
+ }
156
+ }
157
+ function decodeFrame(buffer) {
158
+ if (buffer.length < 2)
159
+ return null;
160
+ const first = buffer[0];
161
+ const second = buffer[1];
162
+ const fin = (first & 0x80) !== 0;
163
+ const opcode = first & 0x0f;
164
+ const masked = (second & 0x80) !== 0;
165
+ let length = second & 0x7f;
166
+ let offset = 2;
167
+ if (length === 126) {
168
+ if (buffer.length < offset + 2)
169
+ return null;
170
+ length = buffer.readUInt16BE(offset);
171
+ offset += 2;
172
+ }
173
+ else if (length === 127) {
174
+ if (buffer.length < offset + 8)
175
+ return null;
176
+ const big = buffer.readBigUInt64BE(offset);
177
+ if (big > BigInt(Number.MAX_SAFE_INTEGER))
178
+ throw new Error("frame too large");
179
+ length = Number(big);
180
+ offset += 8;
181
+ }
182
+ let mask;
183
+ if (masked) {
184
+ if (buffer.length < offset + 4)
185
+ return null;
186
+ mask = buffer.subarray(offset, offset + 4);
187
+ offset += 4;
188
+ }
189
+ if (buffer.length < offset + length)
190
+ return null;
191
+ const raw = buffer.subarray(offset, offset + length);
192
+ const payload = mask ? unmask(raw, mask) : Buffer.from(raw);
193
+ return { fin, opcode, payload, consumed: offset + length };
194
+ }
195
+ function unmask(payload, mask) {
196
+ const out = Buffer.allocUnsafe(payload.length);
197
+ for (let i = 0; i < payload.length; i += 1)
198
+ out[i] = payload[i] ^ mask[i % 4];
199
+ return out;
200
+ }
201
+ function encodeFrame(opcode, payload) {
202
+ const length = payload.length;
203
+ let header;
204
+ if (length < 126) {
205
+ header = Buffer.alloc(2);
206
+ header[1] = length;
207
+ }
208
+ else if (length < 65536) {
209
+ header = Buffer.alloc(4);
210
+ header[1] = 126;
211
+ header.writeUInt16BE(length, 2);
212
+ }
213
+ else {
214
+ header = Buffer.alloc(10);
215
+ header[1] = 127;
216
+ header.writeBigUInt64BE(BigInt(length), 2);
217
+ }
218
+ header[0] = 0x80 | opcode;
219
+ return Buffer.concat([header, payload]);
220
+ }
221
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@appport/server",
3
+ "version": "1.0.0",
4
+ "description": "Server-side AppPort protocol runtime with HTTP and WebSocket bindings.",
5
+ "license": "Apache-2.0",
6
+ "repository": { "type": "git", "url": "git+https://github.com/rkendel1/appport.git", "directory": "packages/server" },
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./node": {
16
+ "types": "./dist/node-entry.d.ts",
17
+ "import": "./dist/node-entry.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc -b",
26
+ "clean": "tsc -b --clean"
27
+ },
28
+ "dependencies": {
29
+ "@appport/protocol": "1.0.0",
30
+ "@appport/core": "1.0.1",
31
+ "@appport/authorization": "1.0.0"
32
+ },
33
+ "publishConfig": { "access": "public" }
34
+ }