@oxy.so/core 7.9.2 → 7.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/cjs/api/storeInstaller.js +46 -0
- package/dist/cjs/index.js +10 -4
- package/dist/esm/api/storeInstaller.js +40 -0
- package/dist/esm/index.js +3 -0
- package/dist/types/api/storeInstaller.d.ts +155 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/api/storeInstaller.ts +158 -0
- package/src/index.ts +15 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The store's installer: how a store installs, opens and updates an application on a machine
|
|
4
|
+
* that installs applications, beside `oxy.store`, which reads the catalogue.
|
|
5
|
+
*
|
|
6
|
+
* `oxy.store` says what the store lists; an installer says what the machine can do with a
|
|
7
|
+
* listing. A runtime that installs applications registers one (OxyOS's Bloom host registers one
|
|
8
|
+
* backed by the system's install service before the application's code runs, OxyOS ADR 0030
|
|
9
|
+
* decision 9; ADR 0053 here). Where none is registered — the web, iOS, Android — there is
|
|
10
|
+
* nothing to install, and a store shows what it shows without one. An application never asks
|
|
11
|
+
* which platform it runs on: it asks whether there is an installer.
|
|
12
|
+
*
|
|
13
|
+
* The installer is the store's hands, never its judge. It is given a listing's slug and nothing
|
|
14
|
+
* else: the machine resolves slug → package → release from the store's signed metadata, verifies
|
|
15
|
+
* it, and asks the person in a sheet of its own that no application can draw or press. The store
|
|
16
|
+
* learns the outcome and nothing of the sheet. Its errors say whether the machine already told the
|
|
17
|
+
* person (`told`), so a store never repeats what the system said.
|
|
18
|
+
*
|
|
19
|
+
* React-free and dependency-free, as everything in `@oxy.so/core`.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.StoreInstallerError = void 0;
|
|
23
|
+
exports.setStoreInstaller = setStoreInstaller;
|
|
24
|
+
exports.getStoreInstaller = getStoreInstaller;
|
|
25
|
+
/** A failure of an installer's request. */
|
|
26
|
+
class StoreInstallerError extends Error {
|
|
27
|
+
constructor(reason, options = {}) {
|
|
28
|
+
super(options.message ?? reason);
|
|
29
|
+
this.name = 'StoreInstallerError';
|
|
30
|
+
this.reason = reason;
|
|
31
|
+
this.told = options.told ?? false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.StoreInstallerError = StoreInstallerError;
|
|
35
|
+
let installer = null;
|
|
36
|
+
/**
|
|
37
|
+
* Registers the machine's installer, or removes it with null. A runtime calls it once, before
|
|
38
|
+
* the application's code runs; nothing else should.
|
|
39
|
+
*/
|
|
40
|
+
function setStoreInstaller(next) {
|
|
41
|
+
installer = next;
|
|
42
|
+
}
|
|
43
|
+
/** The machine's installer, or null where nothing installs applications. */
|
|
44
|
+
function getStoreInstaller() {
|
|
45
|
+
return installer;
|
|
46
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* If a symbol does not appear here, it is NOT part of the public API.
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
25
|
-
exports.
|
|
26
|
-
exports.
|
|
27
|
-
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = void 0;
|
|
24
|
+
exports.getBaseLanguage = exports.FALLBACK_LOCALE = exports.SUPPORTED_LANGUAGES = exports.TopicSource = exports.TopicType = exports.SECURITY_EVENT_SEVERITY_MAP = exports.sessionsArraysEqual = exports.normalizeAndSortSessions = exports.mergeSessions = exports.authenticatedApiCall = exports.withAuthErrorHandling = exports.isAuthenticationError = exports.ensureValidToken = exports.AuthenticationFailedError = exports.SessionSyncRequiredError = exports.normalizeProfileLinks = exports.getNormalizedUserHandle = exports.getCanonicalUserHandle = exports.normalizeUserIdentityOrNull = exports.normalizeUserIdentity = exports.getNormalizedUserId = exports.commonsDeliveryPlatform = exports.pushTargetsFromDelivery = exports.selectCommonsDelivery = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = exports.OxyAppDataIdentifierError = exports.AccountNotOnDeviceError = exports.REPUTATION_CACHE_PREFIX = exports.StoreInstallerError = exports.setStoreInstaller = exports.getStoreInstaller = exports.kindAcceptsAccountCategories = exports.isSelectableAccountCategoryId = exports.SELECTABLE_ACCOUNT_CATEGORY_IDS = exports.MAX_ACCOUNT_CATEGORIES = exports.ACCOUNT_CATEGORY_IDS = exports.buildUserDid = exports.DirectUploadInterruptedError = exports.MAX_UPLOAD_BYTES = exports.assetUrlCacheTTL = exports.ASSET_MULTIPART_UPLOAD_MAX_BYTES = exports.ServiceAssetMetadataError = exports.AssetUrlResolutionError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OxyApiError = exports.OXY_CLOUD_URL = exports.OXY_API_URL = exports.OxyServices = void 0;
|
|
25
|
+
exports.isLocaleLoaded = exports.loadLocale = exports.translate = exports.withRetry = exports.delay = exports.shouldAllowRequest = exports.recordSuccess = exports.recordFailure = exports.calculateBackoffInterval = exports.createCircuitBreakerState = exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = exports.isRetryableError = exports.isNetworkError = exports.isServerError = exports.isRateLimitError = exports.isNotFoundError = exports.isForbiddenError = exports.isUnauthorizedError = exports.isAlreadyRegisteredError = exports.getErrorMessage = exports.getErrorStatus = exports.HttpStatus = exports.getSystemColorScheme = exports.systemPrefersDarkMode = exports.getOppositeTheme = exports.normalizeColorScheme = exports.normalizeTheme = exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.coerceToSupportedLocale = exports.getPrimaryLanguage = exports.getUserLanguages = exports.isRTLLocale = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.isSupportedLocale = exports.normalizeLocale = void 0;
|
|
26
|
+
exports.normalizeMultilineText = exports.normalizeInlineText = exports.validateAndSanitizeUserInput = exports.isValidObjectId = exports.sanitizeHTML = exports.sanitizeString = exports.isValidFileType = exports.isValidFileSize = exports.isValidDate = exports.isValidURL = exports.isValidUUID = exports.isValidObject = exports.isValidArray = exports.isRequiredBoolean = exports.isRequiredNumber = exports.isRequiredString = exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.accountNameInvalidKey = exports.accountNameInvalidMessage = exports.accountNameMaxLength = exports.isValidAccountName = exports.isValidDisplayName = exports.isValidPassword = exports.isValidEmail = exports.ACCOUNT_TITLE_INVALID_MESSAGE = exports.DISPLAY_NAME_INVALID_MESSAGE = exports.MAX_DISPLAY_NAME_LENGTH = exports.PASSWORD_REGEX = exports.EMAIL_REGEX = exports.retryAsync = exports.validateRequiredFields = exports.parseHttpErrorBody = exports.isHttpRequestError = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.buildQueryParams = exports.trustTierLabel = exports.reputationCategoryLabel = exports.accountRoleLabel = exports.accountCategoryLabel = exports.getLocalesVersion = exports.subscribeLocales = void 0;
|
|
27
|
+
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = void 0;
|
|
28
28
|
// The crypto shim MUST stay the first import. The root itself ships no crypto
|
|
29
29
|
// library (`__tests__/rootEntryGraph.test.ts`), but `@oxy.so/protocol`'s root
|
|
30
30
|
// entry (reached by the OAuth/PKCE and device helpers) does, and Metro does not
|
|
@@ -58,6 +58,12 @@ Object.defineProperty(exports, "MAX_ACCOUNT_CATEGORIES", { enumerable: true, get
|
|
|
58
58
|
Object.defineProperty(exports, "SELECTABLE_ACCOUNT_CATEGORY_IDS", { enumerable: true, get: function () { return accounts_1.SELECTABLE_ACCOUNT_CATEGORY_IDS; } });
|
|
59
59
|
Object.defineProperty(exports, "isSelectableAccountCategoryId", { enumerable: true, get: function () { return accounts_1.isSelectableAccountCategoryId; } });
|
|
60
60
|
Object.defineProperty(exports, "kindAcceptsAccountCategories", { enumerable: true, get: function () { return accounts_1.kindAcceptsAccountCategories; } });
|
|
61
|
+
// The store's installer (ADR 0053): what a runtime that installs applications registers beside
|
|
62
|
+
// `oxy.store`, and what a store asks it.
|
|
63
|
+
var storeInstaller_1 = require("./api/storeInstaller");
|
|
64
|
+
Object.defineProperty(exports, "getStoreInstaller", { enumerable: true, get: function () { return storeInstaller_1.getStoreInstaller; } });
|
|
65
|
+
Object.defineProperty(exports, "setStoreInstaller", { enumerable: true, get: function () { return storeInstaller_1.setStoreInstaller; } });
|
|
66
|
+
Object.defineProperty(exports, "StoreInstallerError", { enumerable: true, get: function () { return storeInstaller_1.StoreInstallerError; } });
|
|
61
67
|
var reputation_1 = require("./api/reputation");
|
|
62
68
|
Object.defineProperty(exports, "REPUTATION_CACHE_PREFIX", { enumerable: true, get: function () { return reputation_1.REPUTATION_CACHE_PREFIX; } });
|
|
63
69
|
var devices_1 = require("./api/devices");
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store's installer: how a store installs, opens and updates an application on a machine
|
|
3
|
+
* that installs applications, beside `oxy.store`, which reads the catalogue.
|
|
4
|
+
*
|
|
5
|
+
* `oxy.store` says what the store lists; an installer says what the machine can do with a
|
|
6
|
+
* listing. A runtime that installs applications registers one (OxyOS's Bloom host registers one
|
|
7
|
+
* backed by the system's install service before the application's code runs, OxyOS ADR 0030
|
|
8
|
+
* decision 9; ADR 0053 here). Where none is registered — the web, iOS, Android — there is
|
|
9
|
+
* nothing to install, and a store shows what it shows without one. An application never asks
|
|
10
|
+
* which platform it runs on: it asks whether there is an installer.
|
|
11
|
+
*
|
|
12
|
+
* The installer is the store's hands, never its judge. It is given a listing's slug and nothing
|
|
13
|
+
* else: the machine resolves slug → package → release from the store's signed metadata, verifies
|
|
14
|
+
* it, and asks the person in a sheet of its own that no application can draw or press. The store
|
|
15
|
+
* learns the outcome and nothing of the sheet. Its errors say whether the machine already told the
|
|
16
|
+
* person (`told`), so a store never repeats what the system said.
|
|
17
|
+
*
|
|
18
|
+
* React-free and dependency-free, as everything in `@oxy.so/core`.
|
|
19
|
+
*/
|
|
20
|
+
/** A failure of an installer's request. */
|
|
21
|
+
export class StoreInstallerError extends Error {
|
|
22
|
+
constructor(reason, options = {}) {
|
|
23
|
+
super(options.message ?? reason);
|
|
24
|
+
this.name = 'StoreInstallerError';
|
|
25
|
+
this.reason = reason;
|
|
26
|
+
this.told = options.told ?? false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
let installer = null;
|
|
30
|
+
/**
|
|
31
|
+
* Registers the machine's installer, or removes it with null. A runtime calls it once, before
|
|
32
|
+
* the application's code runs; nothing else should.
|
|
33
|
+
*/
|
|
34
|
+
export function setStoreInstaller(next) {
|
|
35
|
+
installer = next;
|
|
36
|
+
}
|
|
37
|
+
/** The machine's installer, or null where nothing installs applications. */
|
|
38
|
+
export function getStoreInstaller() {
|
|
39
|
+
return installer;
|
|
40
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -34,6 +34,9 @@ export { ASSET_MULTIPART_UPLOAD_MAX_BYTES, assetUrlCacheTTL, MAX_UPLOAD_BYTES }
|
|
|
34
34
|
export { DirectUploadInterruptedError } from './api/directUpload.js';
|
|
35
35
|
export { buildUserDid } from './api/identity.js';
|
|
36
36
|
export { ACCOUNT_CATEGORY_IDS, MAX_ACCOUNT_CATEGORIES, SELECTABLE_ACCOUNT_CATEGORY_IDS, isSelectableAccountCategoryId, kindAcceptsAccountCategories, } from './api/accounts.js';
|
|
37
|
+
// The store's installer (ADR 0053): what a runtime that installs applications registers beside
|
|
38
|
+
// `oxy.store`, and what a store asks it.
|
|
39
|
+
export { getStoreInstaller, setStoreInstaller, StoreInstallerError, } from './api/storeInstaller.js';
|
|
37
40
|
export { REPUTATION_CACHE_PREFIX } from './api/reputation.js';
|
|
38
41
|
export { AccountNotOnDeviceError } from './api/devices.js';
|
|
39
42
|
export { OxyAppDataIdentifierError } from './api/appData.js';
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store's installer: how a store installs, opens and updates an application on a machine
|
|
3
|
+
* that installs applications, beside `oxy.store`, which reads the catalogue.
|
|
4
|
+
*
|
|
5
|
+
* `oxy.store` says what the store lists; an installer says what the machine can do with a
|
|
6
|
+
* listing. A runtime that installs applications registers one (OxyOS's Bloom host registers one
|
|
7
|
+
* backed by the system's install service before the application's code runs, OxyOS ADR 0030
|
|
8
|
+
* decision 9; ADR 0053 here). Where none is registered — the web, iOS, Android — there is
|
|
9
|
+
* nothing to install, and a store shows what it shows without one. An application never asks
|
|
10
|
+
* which platform it runs on: it asks whether there is an installer.
|
|
11
|
+
*
|
|
12
|
+
* The installer is the store's hands, never its judge. It is given a listing's slug and nothing
|
|
13
|
+
* else: the machine resolves slug → package → release from the store's signed metadata, verifies
|
|
14
|
+
* it, and asks the person in a sheet of its own that no application can draw or press. The store
|
|
15
|
+
* learns the outcome and nothing of the sheet. Its errors say whether the machine already told the
|
|
16
|
+
* person (`told`), so a store never repeats what the system said.
|
|
17
|
+
*
|
|
18
|
+
* React-free and dependency-free, as everything in `@oxy.so/core`.
|
|
19
|
+
*/
|
|
20
|
+
/** Where a listing stands on this machine, for the action a store's page shows. */
|
|
21
|
+
export type StoreInstallState =
|
|
22
|
+
/** The store has a release this machine can run, and it is not installed: *Get*. */
|
|
23
|
+
{
|
|
24
|
+
state: 'notInstalled';
|
|
25
|
+
}
|
|
26
|
+
/** Being installed or updated: a progress ring. `fraction` is null while it cannot be told. */
|
|
27
|
+
| {
|
|
28
|
+
state: 'installing';
|
|
29
|
+
fraction: number | null;
|
|
30
|
+
}
|
|
31
|
+
/** Installed and current: *Open*. */
|
|
32
|
+
| {
|
|
33
|
+
state: 'installed';
|
|
34
|
+
version: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Installed, with a newer release: *Update*. `needsConsent` when the newer release asks for
|
|
38
|
+
* more than the installed one, which the machine asks the person for in its own sheet.
|
|
39
|
+
*/
|
|
40
|
+
| {
|
|
41
|
+
state: 'updateAvailable';
|
|
42
|
+
version: string;
|
|
43
|
+
newVersion: string;
|
|
44
|
+
needsConsent: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** The store has no release this machine can run: *Not available for this computer*. */
|
|
47
|
+
| {
|
|
48
|
+
state: 'unavailable';
|
|
49
|
+
};
|
|
50
|
+
/** Why the machine could not do what the store asked. */
|
|
51
|
+
export type StoreInstallerFailure =
|
|
52
|
+
/** The machine's install service is not running. */
|
|
53
|
+
'serviceUnavailable'
|
|
54
|
+
/** The store has no release of it this machine can run. */
|
|
55
|
+
| 'notAvailable'
|
|
56
|
+
/** It is not installed (opening or updating it). */
|
|
57
|
+
| 'notInstalled'
|
|
58
|
+
/** The installer refused the request (it lacks the right to install, or it was not a person's press). */
|
|
59
|
+
| 'refused'
|
|
60
|
+
/** The install or update itself failed (a download, a verification, a compile). */
|
|
61
|
+
| 'failed';
|
|
62
|
+
/** A failure of an installer's request. */
|
|
63
|
+
export declare class StoreInstallerError extends Error {
|
|
64
|
+
readonly reason: StoreInstallerFailure;
|
|
65
|
+
/**
|
|
66
|
+
* Whether the machine already told the person, in its own sheet. A store says nothing more
|
|
67
|
+
* when it did: the system's word is the one the person reads.
|
|
68
|
+
*/
|
|
69
|
+
readonly told: boolean;
|
|
70
|
+
constructor(reason: StoreInstallerFailure, options?: {
|
|
71
|
+
told?: boolean;
|
|
72
|
+
message?: string;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** An update the machine has for an installed application. */
|
|
76
|
+
export interface StoreUpdate {
|
|
77
|
+
/** The installer's own id for the application; what `apply` takes. Never a slug. */
|
|
78
|
+
id: string;
|
|
79
|
+
/** Its name in the person's language, from the store's signed metadata. */
|
|
80
|
+
name: string;
|
|
81
|
+
/** The version installed, and the one the update brings. */
|
|
82
|
+
version: string;
|
|
83
|
+
newVersion: string;
|
|
84
|
+
/** Bytes the machine would fetch: only what it does not have already. */
|
|
85
|
+
downloadSize: number;
|
|
86
|
+
/** What is new, in the person's language, or null when the release says nothing. */
|
|
87
|
+
releaseNotes: string | null;
|
|
88
|
+
/** The update asks for more than the installed version: the machine asks the person first. */
|
|
89
|
+
needsConsent: boolean;
|
|
90
|
+
/** Applied, waiting for the running copy to quit: it runs at its next launch. */
|
|
91
|
+
atNextLaunch: boolean;
|
|
92
|
+
}
|
|
93
|
+
/** The machine's updates for this account: one state, which every page that shows updates reads. */
|
|
94
|
+
export interface StoreUpdates {
|
|
95
|
+
updates: StoreUpdate[];
|
|
96
|
+
/** A check of the store is running. */
|
|
97
|
+
checking: boolean;
|
|
98
|
+
/** When the store was last read (ISO 8601), or null. */
|
|
99
|
+
lastChecked: string | null;
|
|
100
|
+
/** The last check failed. */
|
|
101
|
+
checkFailed: boolean;
|
|
102
|
+
}
|
|
103
|
+
/** The machine's updates, as one state that changes by itself. */
|
|
104
|
+
export interface StoreUpdatesSource {
|
|
105
|
+
/** The state last told, or null before the machine has said. */
|
|
106
|
+
current(): StoreUpdates | null;
|
|
107
|
+
/**
|
|
108
|
+
* The state as it is now, asked of the machine without reading the store. Rejects with a
|
|
109
|
+
* `StoreInstallerError` when the machine cannot say (its install service is not running).
|
|
110
|
+
*/
|
|
111
|
+
read(): Promise<StoreUpdates>;
|
|
112
|
+
/** Reads the store now. A check asked while one runs joins it. */
|
|
113
|
+
check(): Promise<StoreUpdates>;
|
|
114
|
+
/** Applies these updates; one that needs consent is asked in the machine's sheet first. */
|
|
115
|
+
apply(ids: readonly string[]): Promise<void>;
|
|
116
|
+
/** Applies every update, asking for consent in turn after the rest. */
|
|
117
|
+
applyAll(): Promise<void>;
|
|
118
|
+
/** Told each change; returns the unsubscribe. */
|
|
119
|
+
subscribe(listener: (updates: StoreUpdates) => void): () => void;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* What a runtime that installs applications gives a store. Every action that changes anything is
|
|
123
|
+
* asked from a person's press: the machine refuses what the person did not ask for.
|
|
124
|
+
*/
|
|
125
|
+
export interface StoreInstaller {
|
|
126
|
+
/**
|
|
127
|
+
* Where each listing stands. Rejects with a `StoreInstallerError` when the machine cannot say
|
|
128
|
+
* (its install service is not running): a store then shows its usual action and lets the
|
|
129
|
+
* machine say why when it is pressed.
|
|
130
|
+
*/
|
|
131
|
+
status(slugs: readonly string[]): Promise<Record<string, StoreInstallState>>;
|
|
132
|
+
/**
|
|
133
|
+
* Installs a listing's application: the machine's sheet, then the install. Resolves when the
|
|
134
|
+
* person declined in the sheet or the install is done; the progress in between is told to
|
|
135
|
+
* `subscribe`'s listeners as `installing`.
|
|
136
|
+
*/
|
|
137
|
+
install(slug: string): Promise<'installed' | 'declined'>;
|
|
138
|
+
/** Updates it, asking in the machine's sheet when the update needs the person's consent. */
|
|
139
|
+
update(slug: string): Promise<'updated' | 'declined'>;
|
|
140
|
+
/** Removes it and its data, after the machine's sheet. */
|
|
141
|
+
uninstall(slug: string): Promise<'removed' | 'declined'>;
|
|
142
|
+
/** Opens the installed application. */
|
|
143
|
+
open(slug: string): Promise<void>;
|
|
144
|
+
/** Told each listing whose state changed; returns the unsubscribe. */
|
|
145
|
+
subscribe(listener: (slug: string, state: StoreInstallState) => void): () => void;
|
|
146
|
+
/** The account's updates (a store's *Updates* page). */
|
|
147
|
+
readonly updates: StoreUpdatesSource;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Registers the machine's installer, or removes it with null. A runtime calls it once, before
|
|
151
|
+
* the application's code runs; nothing else should.
|
|
152
|
+
*/
|
|
153
|
+
export declare function setStoreInstaller(next: StoreInstaller | null): void;
|
|
154
|
+
/** The machine's installer, or null where nothing installs applications. */
|
|
155
|
+
export declare function getStoreInstaller(): StoreInstaller | null;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export type { AppsApi, AppAssertionsApi, Application, ApplicationType, Applicati
|
|
|
45
45
|
export type { LinkedAccountsApi } from './api/linkedAccounts';
|
|
46
46
|
export type { AgencyApi, AccountCapabilityPolicy, AvailableCapabilityCatalog, CapabilityExecutionAuthorization, CreateDelegationGrantInput, DelegationCatalogBinding, DelegationGrantView, PutAccountCapabilityPolicyInput, UpdateDelegationGrantInput, } from './api/agency';
|
|
47
47
|
export type { StoreApi, StoreCategory, StoreRating, StoreListingSummary, StoreListingDetail, StoreScreenshot, StoreScreenshotPlatform, StoreReview, StoreOwnReview, WriteStoreReviewInput, StoreListingStatus, PublisherListing, WriteListingInput, AddScreenshotInput, UpdateScreenshotInput, StorePage, StorePageOptions, StoreReviewsOptions, } from './api/store';
|
|
48
|
+
export { getStoreInstaller, setStoreInstaller, StoreInstallerError, } from './api/storeInstaller';
|
|
49
|
+
export type { StoreInstallState, StoreInstaller, StoreInstallerFailure, StoreUpdate, StoreUpdates, StoreUpdatesSource, } from './api/storeInstaller';
|
|
48
50
|
export type { BillingApi, SubscriptionPlan, SubscriptionStatus, SubscriptionFeatures, Subscription, Payment, WalletTransactionType, WalletTransactionStatus, WalletTransaction, WalletPagination, WalletTransactionsPage, } from './api/billing';
|
|
49
51
|
export { REPUTATION_CACHE_PREFIX } from './api/reputation';
|
|
50
52
|
export type { ReputationApi, ReputationPage } from './api/reputation';
|
package/package.json
CHANGED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store's installer: how a store installs, opens and updates an application on a machine
|
|
3
|
+
* that installs applications, beside `oxy.store`, which reads the catalogue.
|
|
4
|
+
*
|
|
5
|
+
* `oxy.store` says what the store lists; an installer says what the machine can do with a
|
|
6
|
+
* listing. A runtime that installs applications registers one (OxyOS's Bloom host registers one
|
|
7
|
+
* backed by the system's install service before the application's code runs, OxyOS ADR 0030
|
|
8
|
+
* decision 9; ADR 0053 here). Where none is registered — the web, iOS, Android — there is
|
|
9
|
+
* nothing to install, and a store shows what it shows without one. An application never asks
|
|
10
|
+
* which platform it runs on: it asks whether there is an installer.
|
|
11
|
+
*
|
|
12
|
+
* The installer is the store's hands, never its judge. It is given a listing's slug and nothing
|
|
13
|
+
* else: the machine resolves slug → package → release from the store's signed metadata, verifies
|
|
14
|
+
* it, and asks the person in a sheet of its own that no application can draw or press. The store
|
|
15
|
+
* learns the outcome and nothing of the sheet. Its errors say whether the machine already told the
|
|
16
|
+
* person (`told`), so a store never repeats what the system said.
|
|
17
|
+
*
|
|
18
|
+
* React-free and dependency-free, as everything in `@oxy.so/core`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Where a listing stands on this machine, for the action a store's page shows. */
|
|
22
|
+
export type StoreInstallState =
|
|
23
|
+
/** The store has a release this machine can run, and it is not installed: *Get*. */
|
|
24
|
+
| { state: 'notInstalled' }
|
|
25
|
+
/** Being installed or updated: a progress ring. `fraction` is null while it cannot be told. */
|
|
26
|
+
| { state: 'installing'; fraction: number | null }
|
|
27
|
+
/** Installed and current: *Open*. */
|
|
28
|
+
| { state: 'installed'; version: string }
|
|
29
|
+
/**
|
|
30
|
+
* Installed, with a newer release: *Update*. `needsConsent` when the newer release asks for
|
|
31
|
+
* more than the installed one, which the machine asks the person for in its own sheet.
|
|
32
|
+
*/
|
|
33
|
+
| { state: 'updateAvailable'; version: string; newVersion: string; needsConsent: boolean }
|
|
34
|
+
/** The store has no release this machine can run: *Not available for this computer*. */
|
|
35
|
+
| { state: 'unavailable' };
|
|
36
|
+
|
|
37
|
+
/** Why the machine could not do what the store asked. */
|
|
38
|
+
export type StoreInstallerFailure =
|
|
39
|
+
/** The machine's install service is not running. */
|
|
40
|
+
| 'serviceUnavailable'
|
|
41
|
+
/** The store has no release of it this machine can run. */
|
|
42
|
+
| 'notAvailable'
|
|
43
|
+
/** It is not installed (opening or updating it). */
|
|
44
|
+
| 'notInstalled'
|
|
45
|
+
/** The installer refused the request (it lacks the right to install, or it was not a person's press). */
|
|
46
|
+
| 'refused'
|
|
47
|
+
/** The install or update itself failed (a download, a verification, a compile). */
|
|
48
|
+
| 'failed';
|
|
49
|
+
|
|
50
|
+
/** A failure of an installer's request. */
|
|
51
|
+
export class StoreInstallerError extends Error {
|
|
52
|
+
readonly reason: StoreInstallerFailure;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the machine already told the person, in its own sheet. A store says nothing more
|
|
55
|
+
* when it did: the system's word is the one the person reads.
|
|
56
|
+
*/
|
|
57
|
+
readonly told: boolean;
|
|
58
|
+
|
|
59
|
+
constructor(reason: StoreInstallerFailure, options: { told?: boolean; message?: string } = {}) {
|
|
60
|
+
super(options.message ?? reason);
|
|
61
|
+
this.name = 'StoreInstallerError';
|
|
62
|
+
this.reason = reason;
|
|
63
|
+
this.told = options.told ?? false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** An update the machine has for an installed application. */
|
|
68
|
+
export interface StoreUpdate {
|
|
69
|
+
/** The installer's own id for the application; what `apply` takes. Never a slug. */
|
|
70
|
+
id: string;
|
|
71
|
+
/** Its name in the person's language, from the store's signed metadata. */
|
|
72
|
+
name: string;
|
|
73
|
+
/** The version installed, and the one the update brings. */
|
|
74
|
+
version: string;
|
|
75
|
+
newVersion: string;
|
|
76
|
+
/** Bytes the machine would fetch: only what it does not have already. */
|
|
77
|
+
downloadSize: number;
|
|
78
|
+
/** What is new, in the person's language, or null when the release says nothing. */
|
|
79
|
+
releaseNotes: string | null;
|
|
80
|
+
/** The update asks for more than the installed version: the machine asks the person first. */
|
|
81
|
+
needsConsent: boolean;
|
|
82
|
+
/** Applied, waiting for the running copy to quit: it runs at its next launch. */
|
|
83
|
+
atNextLaunch: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The machine's updates for this account: one state, which every page that shows updates reads. */
|
|
87
|
+
export interface StoreUpdates {
|
|
88
|
+
updates: StoreUpdate[];
|
|
89
|
+
/** A check of the store is running. */
|
|
90
|
+
checking: boolean;
|
|
91
|
+
/** When the store was last read (ISO 8601), or null. */
|
|
92
|
+
lastChecked: string | null;
|
|
93
|
+
/** The last check failed. */
|
|
94
|
+
checkFailed: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The machine's updates, as one state that changes by itself. */
|
|
98
|
+
export interface StoreUpdatesSource {
|
|
99
|
+
/** The state last told, or null before the machine has said. */
|
|
100
|
+
current(): StoreUpdates | null;
|
|
101
|
+
/**
|
|
102
|
+
* The state as it is now, asked of the machine without reading the store. Rejects with a
|
|
103
|
+
* `StoreInstallerError` when the machine cannot say (its install service is not running).
|
|
104
|
+
*/
|
|
105
|
+
read(): Promise<StoreUpdates>;
|
|
106
|
+
/** Reads the store now. A check asked while one runs joins it. */
|
|
107
|
+
check(): Promise<StoreUpdates>;
|
|
108
|
+
/** Applies these updates; one that needs consent is asked in the machine's sheet first. */
|
|
109
|
+
apply(ids: readonly string[]): Promise<void>;
|
|
110
|
+
/** Applies every update, asking for consent in turn after the rest. */
|
|
111
|
+
applyAll(): Promise<void>;
|
|
112
|
+
/** Told each change; returns the unsubscribe. */
|
|
113
|
+
subscribe(listener: (updates: StoreUpdates) => void): () => void;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* What a runtime that installs applications gives a store. Every action that changes anything is
|
|
118
|
+
* asked from a person's press: the machine refuses what the person did not ask for.
|
|
119
|
+
*/
|
|
120
|
+
export interface StoreInstaller {
|
|
121
|
+
/**
|
|
122
|
+
* Where each listing stands. Rejects with a `StoreInstallerError` when the machine cannot say
|
|
123
|
+
* (its install service is not running): a store then shows its usual action and lets the
|
|
124
|
+
* machine say why when it is pressed.
|
|
125
|
+
*/
|
|
126
|
+
status(slugs: readonly string[]): Promise<Record<string, StoreInstallState>>;
|
|
127
|
+
/**
|
|
128
|
+
* Installs a listing's application: the machine's sheet, then the install. Resolves when the
|
|
129
|
+
* person declined in the sheet or the install is done; the progress in between is told to
|
|
130
|
+
* `subscribe`'s listeners as `installing`.
|
|
131
|
+
*/
|
|
132
|
+
install(slug: string): Promise<'installed' | 'declined'>;
|
|
133
|
+
/** Updates it, asking in the machine's sheet when the update needs the person's consent. */
|
|
134
|
+
update(slug: string): Promise<'updated' | 'declined'>;
|
|
135
|
+
/** Removes it and its data, after the machine's sheet. */
|
|
136
|
+
uninstall(slug: string): Promise<'removed' | 'declined'>;
|
|
137
|
+
/** Opens the installed application. */
|
|
138
|
+
open(slug: string): Promise<void>;
|
|
139
|
+
/** Told each listing whose state changed; returns the unsubscribe. */
|
|
140
|
+
subscribe(listener: (slug: string, state: StoreInstallState) => void): () => void;
|
|
141
|
+
/** The account's updates (a store's *Updates* page). */
|
|
142
|
+
readonly updates: StoreUpdatesSource;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let installer: StoreInstaller | null = null;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Registers the machine's installer, or removes it with null. A runtime calls it once, before
|
|
149
|
+
* the application's code runs; nothing else should.
|
|
150
|
+
*/
|
|
151
|
+
export function setStoreInstaller(next: StoreInstaller | null): void {
|
|
152
|
+
installer = next;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The machine's installer, or null where nothing installs applications. */
|
|
156
|
+
export function getStoreInstaller(): StoreInstaller | null {
|
|
157
|
+
return installer;
|
|
158
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -206,6 +206,21 @@ export type {
|
|
|
206
206
|
StorePageOptions,
|
|
207
207
|
StoreReviewsOptions,
|
|
208
208
|
} from './api/store';
|
|
209
|
+
// The store's installer (ADR 0053): what a runtime that installs applications registers beside
|
|
210
|
+
// `oxy.store`, and what a store asks it.
|
|
211
|
+
export {
|
|
212
|
+
getStoreInstaller,
|
|
213
|
+
setStoreInstaller,
|
|
214
|
+
StoreInstallerError,
|
|
215
|
+
} from './api/storeInstaller';
|
|
216
|
+
export type {
|
|
217
|
+
StoreInstallState,
|
|
218
|
+
StoreInstaller,
|
|
219
|
+
StoreInstallerFailure,
|
|
220
|
+
StoreUpdate,
|
|
221
|
+
StoreUpdates,
|
|
222
|
+
StoreUpdatesSource,
|
|
223
|
+
} from './api/storeInstaller';
|
|
209
224
|
export type {
|
|
210
225
|
BillingApi,
|
|
211
226
|
SubscriptionPlan,
|