@snap/camera-kit 0.8.0 → 0.9.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/docs/html/assets/main.js +57 -53
- package/docs/html/assets/search.js +1 -1
- package/docs/html/assets/style.css +504 -362
- package/docs/html/classes/CameraKit.html +113 -47
- package/docs/html/classes/CameraKitSession.html +202 -142
- package/docs/html/classes/CameraKitSource.html +124 -60
- package/docs/html/classes/LensPerformanceMeasurement.html +112 -46
- package/docs/html/classes/LensPerformanceMetrics.html +97 -32
- package/docs/html/classes/LensRepository.html +130 -66
- package/docs/html/classes/LensSources.html +98 -32
- package/docs/html/classes/Transform2D.html +111 -43
- package/docs/html/classes/TypedCustomEvent.html +109 -47
- package/docs/html/classes/TypedEventTarget.html +125 -65
- package/docs/html/functions/Injectable.html +113 -120
- package/docs/html/functions/bootstrapCameraKit.html +100 -104
- package/docs/html/functions/createExtension.html +90 -94
- package/docs/html/functions/createImageSource.html +90 -93
- package/docs/html/functions/createMediaStreamSource.html +90 -93
- package/docs/html/functions/createUserMediaSource.html +92 -96
- package/docs/html/functions/createVideoSource.html +90 -93
- package/docs/html/functions/estimateLensPerformance.html +88 -92
- package/docs/html/functions/getRequiredBootstrapURLs.html +90 -94
- package/docs/html/functions/lensSourcesFactory.html +88 -91
- package/docs/html/functions/uriHandlersFactory.html +88 -91
- package/docs/html/index.html +134 -170
- package/docs/html/interfaces/CameraKitBootstrapConfiguration.html +115 -49
- package/docs/html/interfaces/CameraKitSourceSubscriber.html +111 -45
- package/docs/html/interfaces/ComputedFrameMetrics.html +98 -32
- package/docs/html/interfaces/CreateSessionOptions.html +95 -29
- package/docs/html/interfaces/EstimatedLensPerformance.html +98 -32
- package/docs/html/interfaces/Lens.html +115 -49
- package/docs/html/interfaces/LensSource.html +107 -41
- package/docs/html/interfaces/MediaStreamSourceOptions.html +94 -28
- package/docs/html/interfaces/UriCancelRequest.html +94 -28
- package/docs/html/interfaces/UriHandler.html +108 -42
- package/docs/html/interfaces/UriRequest.html +106 -40
- package/docs/html/interfaces/UriResponse.html +106 -40
- package/docs/html/interfaces/VideoSourceOptions.html +90 -24
- package/docs/html/modules.html +161 -164
- package/docs/html/types/AssetLoader.html +91 -94
- package/docs/html/types/AssetTiming.html +85 -88
- package/docs/html/types/BenchmarkError.html +85 -88
- package/docs/html/types/BootstrapError.html +86 -89
- package/docs/html/types/CacheKeyNotFoundError.html +85 -88
- package/docs/html/types/CameraKitDeviceInfo.html +87 -90
- package/docs/html/types/CameraKitSessionEventListener.html +86 -89
- package/docs/html/types/CameraKitSessionEvents.html +88 -91
- package/docs/html/types/CameraKitSourceError.html +85 -88
- package/docs/html/types/CameraKitSourceInfo.html +85 -88
- package/docs/html/types/CameraKitSourceOptions.html +88 -92
- package/docs/html/types/ConfigurationError.html +86 -89
- package/docs/html/types/Keyboard.html +108 -111
- package/docs/html/types/KeyboardEvents.html +86 -89
- package/docs/html/types/LegalError.html +85 -88
- package/docs/html/types/LensAssetError.html +85 -88
- package/docs/html/types/LensContentValidationError.html +85 -88
- package/docs/html/types/LensError.html +85 -88
- package/docs/html/types/LensExecutionError.html +86 -89
- package/docs/html/types/LensImagePickerError.html +85 -88
- package/docs/html/types/LensLaunchParams.html +85 -88
- package/docs/html/types/LensMetricsEvents.html +86 -89
- package/docs/html/types/LensPerformanceCluster.html +85 -88
- package/docs/html/types/LensView.html +85 -88
- package/docs/html/types/LensWait.html +85 -88
- package/docs/html/types/PersistentStoreError.html +85 -88
- package/docs/html/types/PlatformNotSupportedError.html +86 -89
- package/docs/html/types/PublicContainer.html +85 -88
- package/docs/html/types/RenderTarget.html +85 -88
- package/docs/html/types/Uri.html +85 -88
- package/docs/html/types/UriHandlers.html +86 -89
- package/docs/html/types/WebGLError.html +85 -88
- package/docs/html/variables/extensionRequestContext.html +85 -88
- package/docs/md/README.md +1 -1
- package/docs/md/classes/CameraKit.md +1 -1
- package/docs/md/classes/CameraKitSession.md +1 -1
- package/docs/md/classes/CameraKitSource.md +1 -1
- package/docs/md/classes/LensPerformanceMeasurement.md +1 -1
- package/docs/md/classes/LensPerformanceMetrics.md +1 -1
- package/docs/md/classes/LensRepository.md +3 -3
- package/docs/md/classes/LensSources.md +1 -1
- package/docs/md/classes/Transform2D.md +3 -1
- package/docs/md/classes/TypedCustomEvent.md +1 -1
- package/docs/md/classes/TypedEventTarget.md +3 -3
- package/docs/md/interfaces/CameraKitBootstrapConfiguration.md +1 -1
- package/docs/md/interfaces/CameraKitSourceSubscriber.md +1 -1
- package/docs/md/interfaces/ComputedFrameMetrics.md +1 -1
- package/docs/md/interfaces/CreateSessionOptions.md +1 -1
- package/docs/md/interfaces/EstimatedLensPerformance.md +1 -1
- package/docs/md/interfaces/Lens.md +1 -1
- package/docs/md/interfaces/LensSource.md +1 -1
- package/docs/md/interfaces/MediaStreamSourceOptions.md +1 -1
- package/docs/md/interfaces/UriCancelRequest.md +1 -1
- package/docs/md/interfaces/UriHandler.md +1 -1
- package/docs/md/interfaces/UriRequest.md +1 -1
- package/docs/md/interfaces/UriResponse.md +1 -1
- package/docs/md/interfaces/VideoSourceOptions.md +1 -1
- package/docs/md/modules.md +3 -3
- package/lib/CameraKit.d.ts +7 -7
- package/lib/__tests__/data.d.ts +1 -1
- package/lib/__tests__/deferred.d.ts +1 -1
- package/lib/__tests__/jest.matchers.d.ts +1 -1
- package/lib/benchmark/estimateLensPerformanceCluster.d.ts +2 -2
- package/lib/bootstrapCameraKit.d.ts +1 -1
- package/lib/common/cameraKitUserAgent.d.ts +1 -1
- package/lib/common/localization.d.ts +8 -4
- package/lib/common/localization.js.map +1 -1
- package/lib/common/memoize.d.ts +2 -2
- package/lib/common/pageVisibility.js +1 -1
- package/lib/common/pageVisibility.js.map +1 -1
- package/lib/common/typeguards.d.ts +2 -2
- package/lib/common/types.d.ts +2 -2
- package/lib/common/validate.js +20 -12
- package/lib/common/validate.js.map +1 -1
- package/lib/configuration.d.ts +1 -1
- package/lib/configuration.js.map +1 -1
- package/lib/configurationOverrides.d.ts +1 -1
- package/lib/dependency-injection/Container.d.ts +5 -6
- package/lib/dependency-injection/Container.js +1 -1
- package/lib/dependency-injection/Container.js.map +1 -1
- package/lib/dependency-injection/PartialContainer.d.ts +10 -6
- package/lib/dependency-injection/PartialContainer.js.map +1 -1
- package/lib/dependency-injection/RootServices.d.ts +2 -2
- package/lib/dependency-injection/types.d.ts +9 -9
- package/lib/dependency-injection/types.js.map +1 -1
- package/lib/environment.json +1 -1
- package/lib/events/TypedCustomEvent.d.ts +1 -1
- package/lib/events/TypedEventTarget.d.ts +2 -2
- package/lib/events/scan.d.ts +1 -1
- package/lib/events/scan.js +3 -3
- package/lib/events/scan.js.map +1 -1
- package/lib/extensions/UriHandlers.d.ts +1 -1
- package/lib/generated-proto/blizzard/cameraKitEvents.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js +3 -3
- package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/export.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/export.js +9 -9
- package/lib/generated-proto/pb_schema/camera_kit/v3/export.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js +2 -2
- package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/lens.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js +17 -17
- package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js +3 -3
- package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js.map +1 -1
- package/lib/generated-proto/pb_schema/camera_kit/v3/service.d.ts +4 -4
- package/lib/generated-proto/pb_schema/camera_kit/v3/service.js +25 -25
- package/lib/generated-proto/pb_schema/camera_kit/v3/service.js.map +1 -1
- package/lib/generated-proto/pb_schema/cdp/cof/benchmark.d.ts +4 -4
- package/lib/generated-proto/pb_schema/cdp/cof/circumstance_service.d.ts +4533 -333
- package/lib/generated-proto/pb_schema/cdp/cof/config_request.d.ts +4 -4
- package/lib/generated-proto/pb_schema/cdp/cof/config_response.d.ts +572 -32
- package/lib/generated-proto/pb_schema/cdp/cof/config_result.d.ts +4 -4
- package/lib/generated-proto/pb_schema/cdp/cof/debug_info.d.ts +4 -4
- package/lib/generated-proto/pb_schema/common/ruid.d.ts +4 -4
- package/lib/generated-proto/pb_schema/common/value.d.ts +4 -4
- package/lib/generated-proto/pb_schema/google/api/http.d.ts +4 -4
- package/lib/generated-proto/pb_schema/google/protobuf/any.d.ts +4 -4
- package/lib/generated-proto/pb_schema/google/protobuf/descriptor.d.ts +4 -4
- package/lib/generated-proto/pb_schema/google/protobuf/timestamp.d.ts +4 -4
- package/lib/generated-proto/pb_schema/google/protobuf/wrappers.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/geocircle.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/geopoint.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/launch_params.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/launchdata.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/lures.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/persistent_store.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/snappable.d.ts +4 -4
- package/lib/generated-proto/pb_schema/lenses/user_data.d.ts +4 -4
- package/lib/handlers/HandlerChainBuilder.d.ts +3 -3
- package/lib/handlers/arrayBufferParsingHandler.d.ts +2 -2
- package/lib/handlers/arrayBufferParsingHandler.js.map +1 -1
- package/lib/handlers/cameraKitServiceFetchHandlerFactory.d.ts +1 -1
- package/lib/handlers/defaultFetchHandler.d.ts +1 -1
- package/lib/handlers/headersModifyingFetchHandler.js +5 -1
- package/lib/handlers/headersModifyingFetchHandler.js.map +1 -1
- package/lib/handlers/noCorsRetryingFetchHandler.js +4 -3
- package/lib/handlers/noCorsRetryingFetchHandler.js.map +1 -1
- package/lib/handlers/requestStateEmittingHandler.d.ts +2 -2
- package/lib/handlers/requestStateEmittingHandler.js.map +1 -1
- package/lib/handlers/responseCachingHandler.d.ts +1 -1
- package/lib/handlers/responseCachingHandler.js.map +1 -1
- package/lib/handlers/retryingHandler.d.ts +7 -0
- package/lib/handlers/retryingHandler.js +14 -5
- package/lib/handlers/retryingHandler.js.map +1 -1
- package/lib/legal/legalPrompt.d.ts +1 -1
- package/lib/legal/legalPrompt.js.map +1 -1
- package/lib/legal/legalState.d.ts +1 -1
- package/lib/legal/legalState.js.map +1 -1
- package/lib/lens/Lens.d.ts +1 -1
- package/lib/lens/LensLaunchParams.d.ts +2 -2
- package/lib/lens/LensRepository.d.ts +7 -8
- package/lib/lens/LensRepository.js.map +1 -1
- package/lib/lens/assets/LensAssetRepository.d.ts +2 -2
- package/lib/lens/assets/LensAssetsProvider.d.ts +1 -1
- package/lib/lens/assets/deviceDependentAssetLoader.d.ts +1 -1
- package/lib/lens/assets/remoteMediaAssetLoaderFactory.d.ts +1 -1
- package/lib/lens/assets/staticAssetLoader.d.ts +1 -1
- package/lib/lens-core-module/generated-types.d.ts +29 -29
- package/lib/lens-core-module/loader/lensCoreFactory.d.ts +1 -1
- package/lib/lensCoreWasmVersions.json +3 -3
- package/lib/logger/logger.d.ts +2 -2
- package/lib/media-sources/CameraKitSource.d.ts +3 -3
- package/lib/media-sources/CameraKitSource.js.map +1 -1
- package/lib/media-sources/FunctionSource.d.ts +1 -1
- package/lib/metrics/businessEventsReporter.d.ts +4 -4
- package/lib/metrics/businessEventsReporter.js.map +1 -1
- package/lib/metrics/metricsEventTarget.d.ts +5 -5
- package/lib/metrics/metricsHandler.d.ts +1 -1
- package/lib/metrics/operationalMetricsReporter.d.ts +2 -2
- package/lib/metrics/reporters/reportBenchmarks.d.ts +1 -1
- package/lib/metrics/reporters/reportLegalState.d.ts +1 -1
- package/lib/metrics/reporters/reportLensAndAssetDownload.d.ts +4 -4
- package/lib/metrics/reporters/reportLensValidationFailed.d.ts +1 -1
- package/lib/metrics/reporters/reportLensView.d.ts +1 -1
- package/lib/metrics/reporters/reportLensView.js +1 -1
- package/lib/metrics/reporters/reportLensView.js.map +1 -1
- package/lib/metrics/reporters/reportLensWait.d.ts +1 -1
- package/lib/metrics/reporters/reportUserSession.d.ts +1 -1
- package/lib/namedErrors.d.ts +17 -17
- package/lib/persistence/Persistence.d.ts +1 -1
- package/lib/remote-configuration/cofHandler.d.ts +1 -1
- package/lib/remote-configuration/cofHandler.js +7 -2
- package/lib/remote-configuration/cofHandler.js.map +1 -1
- package/lib/session/CameraKitSession.d.ts +1 -1
- package/lib/session/CameraKitSession.js.map +1 -1
- package/lib/session/CameraKitSessionEvents.d.ts +3 -3
- package/lib/session/LensKeyboard.d.ts +2 -2
- package/lib/session/LensPerformanceMetrics.js.map +1 -1
- package/lib/session/lensState.d.ts +2 -2
- package/lib/session/lensState.js.map +1 -1
- package/lib/session/sessionState.d.ts +1 -1
- package/lib/transforms/Transform2D.js +2 -1
- package/lib/transforms/Transform2D.js.map +1 -1
- package/package.json +14 -14
- package/docs/html/assets/widgets.png +0 -0
- package/docs/html/assets/widgets@2x.png +0 -0
package/lib/CameraKit.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { LensWait } from "./metrics/reporters/reportLensWait";
|
|
|
16
16
|
* @category Lenses
|
|
17
17
|
* @category Metrics
|
|
18
18
|
*/
|
|
19
|
-
export
|
|
19
|
+
export type LensMetricsEvents = TypedCustomEvent<LensView["name"], LensView> | TypedCustomEvent<LensWait["name"], LensWait>;
|
|
20
20
|
/**
|
|
21
21
|
* Options available when creating a {@link CameraKitSession}.
|
|
22
22
|
*
|
|
@@ -113,7 +113,7 @@ export declare const cameraKitFactory: {
|
|
|
113
113
|
token: "metricsEventTarget";
|
|
114
114
|
dependencies: [];
|
|
115
115
|
}, {
|
|
116
|
-
(args_0: import("./configuration").CameraKitConfiguration, args_1: import("./handlers").FetchHandler
|
|
116
|
+
(args_0: import("./configuration").CameraKitConfiguration, args_1: import("./handlers").FetchHandler): import("./handlers/HandlerChainBuilder").Handler<RequestInfo, Response, RequestInit | undefined>;
|
|
117
117
|
token: "cameraKitServiceFetchHandler";
|
|
118
118
|
dependencies: readonly ["configuration", "defaultFetchHandler"];
|
|
119
119
|
}, {
|
|
@@ -121,7 +121,7 @@ export declare const cameraKitFactory: {
|
|
|
121
121
|
token: "remoteConfiguration";
|
|
122
122
|
dependencies: readonly ["configuration"];
|
|
123
123
|
}, {
|
|
124
|
-
(args_0: import("./handlers").FetchHandler
|
|
124
|
+
(args_0: import("./handlers").FetchHandler, args_1: import("./handlers").FetchHandler, args_2: import("./lens").LensSources, args_3: import("./lens").LensAssetRepository): LensRepository;
|
|
125
125
|
token: "LensRepository";
|
|
126
126
|
dependencies: readonly ["cameraKitServiceFetchHandler", "defaultFetchHandler", "lensSources", "lensAssetRepository"];
|
|
127
127
|
}, {
|
|
@@ -129,11 +129,11 @@ export declare const cameraKitFactory: {
|
|
|
129
129
|
token: "lensPersistenceStore";
|
|
130
130
|
dependencies: readonly ["lensCore"];
|
|
131
131
|
}, {
|
|
132
|
-
(args_0: import("./handlers").FetchHandler
|
|
132
|
+
(args_0: import("./handlers").FetchHandler): import("./handlers/HandlerChainBuilder").Handler<RequestInfo, Response, RequestInit | undefined>;
|
|
133
133
|
token: "metricsHandler";
|
|
134
134
|
dependencies: readonly ["cameraKitServiceFetchHandler"];
|
|
135
135
|
}, {
|
|
136
|
-
(args_0: import("./handlers").FetchHandler
|
|
136
|
+
(args_0: import("./handlers").FetchHandler): import("./metrics/operationalMetricsReporter").OperationalMetricsReporter;
|
|
137
137
|
token: "operationalMetricsReporter";
|
|
138
138
|
dependencies: readonly ["metricsHandler"];
|
|
139
139
|
}, {
|
|
@@ -141,11 +141,11 @@ export declare const cameraKitFactory: {
|
|
|
141
141
|
token: "lensAssetRepository";
|
|
142
142
|
dependencies: readonly ["lensCore", "deviceDependentAssetLoader", "remoteMediaAssetLoader", "staticAssetLoader", "metricsEventTarget"];
|
|
143
143
|
}, {
|
|
144
|
-
(args_0: import("./handlers").FetchHandler
|
|
144
|
+
(args_0: import("./handlers").FetchHandler, args_1: import("./remote-configuration/remoteConfiguration").RemoteConfiguration): import("./lens").AssetLoader;
|
|
145
145
|
token: "deviceDependentAssetLoader";
|
|
146
146
|
dependencies: readonly ["defaultFetchHandler", "remoteConfiguration"];
|
|
147
147
|
}, {
|
|
148
|
-
(args_0: import("./handlers").FetchHandler
|
|
148
|
+
(args_0: import("./handlers").FetchHandler): import("./lens").AssetLoader;
|
|
149
149
|
token: "staticAssetLoader";
|
|
150
150
|
dependencies: readonly ["defaultFetchHandler"];
|
|
151
151
|
}, {
|
package/lib/__tests__/data.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { LensCoreModule, AssetType as LensCoreAssetType } from "../lens-core-mod
|
|
|
4
4
|
export declare const falsyValues: readonly [false, null, undefined, 0, ""];
|
|
5
5
|
export declare const truthyValues: readonly [true, 1, {}, Date, readonly []];
|
|
6
6
|
export declare function createLensFixture(name: string, content?: Partial<ContentProto>): LensProto;
|
|
7
|
-
export
|
|
7
|
+
export type LensCoreMock = Pick<jest.Mocked<LensCoreModule>, "AssetType" | "CanvasType" | "InterfaceAction" | "InterfaceControl" | "ExternalMediaOrientation" | "initialize" | "setRemoteAssetsProvider" | "provideRemoteAssetsResponse" | "getOutputCanvases" | "setRenderLoopMode" | "RenderLoopMode" | "setOnFrameProcessedCallback" | "setClientInterfaceRequestHandler" | "provideExternalImage" | "provideExternalVideo" | "registerSavePersistentStoreCallback">;
|
|
8
8
|
export declare const AssetType: Record<keyof LensCoreModule["AssetType"], LensCoreAssetType>;
|
|
9
9
|
export declare function createLensCore(): LensCoreMock;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @category Bootstrapping and Configuration */
|
|
2
|
-
export
|
|
2
|
+
export type LensPerformanceCluster = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
3
|
/** @internal */
|
|
4
|
-
export
|
|
4
|
+
export type BenchmarkResult = {
|
|
5
5
|
name: string;
|
|
6
6
|
value: number;
|
|
7
7
|
};
|
|
@@ -9,7 +9,7 @@ import { PartialContainer } from "./dependency-injection/PartialContainer";
|
|
|
9
9
|
*
|
|
10
10
|
* @category Bootstrapping and Configuration
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
12
|
+
export type PublicContainer = Container<PublicServices>;
|
|
13
13
|
/**
|
|
14
14
|
* Bootstrap CameraKit. This will download the WebAssembly code which powers CameraKit's rendering engine, and return
|
|
15
15
|
* an instance of {@link CameraKit}.
|
|
@@ -27,15 +27,19 @@
|
|
|
27
27
|
* We use the en_US string object to define all localizable stringIds and their types (either a TemplateFunction or a
|
|
28
28
|
* plain string).
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
type LocalizableStrings = typeof en_US;
|
|
31
|
+
type TemplateFunction<K extends readonly string[], V extends {
|
|
32
32
|
[key in K[number]]: string;
|
|
33
|
-
}) => string;
|
|
33
|
+
}> = (values: V) => string;
|
|
34
34
|
/**
|
|
35
35
|
* Strings for each language are defined blow.
|
|
36
36
|
*/
|
|
37
37
|
declare const en_US: {
|
|
38
|
-
legalPromptMessage: TemplateFunction<readonly ["privacyPolicyUrl", "termsOfServiceUrl", "learnMoreUrl"]
|
|
38
|
+
legalPromptMessage: TemplateFunction<readonly ["privacyPolicyUrl", "termsOfServiceUrl", "learnMoreUrl"], {
|
|
39
|
+
privacyPolicyUrl: string;
|
|
40
|
+
termsOfServiceUrl: string;
|
|
41
|
+
learnMoreUrl: string;
|
|
42
|
+
}>;
|
|
39
43
|
legalPromptAccept: string;
|
|
40
44
|
legalPromptReject: string;
|
|
41
45
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/common/localization.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAoC1D,SAAS,YAAY,CACjB,IAAO;IAEP,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/common/localization.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAoC1D,SAAS,YAAY,CACjB,IAAO;IAEP,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAS,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,CAAC,eAAkC,EAAE,EAAE;YAC/C,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC;YACxC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;iBACnB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAY,EAAE,EAAE,WAAC,OAAA,GAAG,MAAA,MAAM,CAAC,GAAG,CAAC,mCAAI,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,CAAA,EAAA,CAAC,CAAC;iBAC5E,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,kBAAkB,GAAG,YAAY,CAAC,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC;AAEnG;;GAEG;AAEH,yBAAyB;AACzB,2DAA2D;AAC3D,wFAAwF;AACxF,MAAM,KAAK,GAAG;IACV,kBAAkB,EAAE,kBAAkB,CAClC,CAAC,GAAG,EAAE,EAAE,CACJ,GAAG,CAAA,4DAA4D,CAAC;8DACd,CAAC;8FAC+B,CAAC;uGACQ,CAClG;IACD,iBAAiB,EAAE,SAAS;IAC5B,iBAAiB,EAAE,SAAS;CAC/B,CAAC;AAEF;;GAEG;AAEH,MAAM,UAAU,GAA0C;IACtD,KAAK;CACR,CAAC;AAEF,MAAM,gBAAgB,GAAG,MAAA,UAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC,mCAAI,KAAK,CAAC;AAExE,MAAM,UAAU,eAAe,CAAsC,QAAY;IAC7E,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import { cameraKitUserAgent } from \"./cameraKitUserAgent\";\n\n/**\n * This implementation is limited by how TypeScript currently implements tag function for template literals.\n *\n * The way tag functions are typed by the TypeScript compiler limits their usefulness, for two reasons:\n *\n * 1. Specific literal types are not inferred from interpolation expressions -- the following does not work:\n * ```ts\n * function tag<K extends readonly string[]>(strings: readonly string[], ...keys: K): string { ... }\n * tag`This is a ${\"test\"} template.` // the K type parameter is not correctly inferred as `readonly ['test']`\n * ```\n * 2. The return type of a function used as a tag function will always be `string` -- the following does not work:\n * ```ts\n * function tag<K extends readonly string[]>(\n * strings: readonly string[],\n * ...keys: K\n * ): (values: {[k in K[number]]: string}) => string { ... }\n *\n * const template = tag`This is a ${\"test\"} template` // TS infers the type of `template` as `string` -- clearly wrong.\n * ```\n *\n * An attempt is made here to work around those limitations and still provide a reasonably amount of type safety without\n * adding too much verbosity.\n *\n * See https://github.com/microsoft/TypeScript/pull/49552\n */\n\n/**\n * We use the en_US string object to define all localizable stringIds and their types (either a TemplateFunction or a\n * plain string).\n */\ntype LocalizableStrings = typeof en_US;\n\ntype TemplateFunction<K extends readonly string[], V extends { [key in K[number]]: string }> = (values: V) => string;\n\nfunction makeTemplate<const K extends readonly string[], V extends { [key in K[number]]: string }>(\n keys: K\n): (template: (tag: (strings: readonly string[], ...keys: 0[]) => string) => string) => TemplateFunction<K, V> {\n return (template) => (values: V) => {\n const tag = (readonlyStrings: readonly string[]) => {\n const strings = readonlyStrings.slice();\n return [strings.shift()]\n .concat(keys.map((key: keyof V) => `${values[key] ?? \"\"}${strings.shift()}`))\n .concat(strings)\n .join(\"\");\n };\n return template(tag);\n };\n}\n\n/**\n * Any strings which are templated (i.e. require runtime values) are defined below.\n */\nconst legalPromptMessage = makeTemplate([\"privacyPolicyUrl\", \"termsOfServiceUrl\", \"learnMoreUrl\"]);\n\n/**\n * Strings for each language are defined blow.\n */\n\n// en_US is used both to:\n// A) define the set of strings which can be localized and\n// B) provide a default set of strings in case a specific localization cannot be found.\nconst en_US = {\n legalPromptMessage: legalPromptMessage(\n (tag) =>\n tag`By using Lenses, you acknowledge reading Snap's <a href=\"${0}\" target=\"_blank\">\n Privacy Policy</a> and agree to Snap's <a href=\"${0}\" target=\"_blank\">Terms of Service</a>.\n Some Lenses use information about your face, hands, and voice to work. <a href=\"${0}\"\n target=\"_blank\">Learn More</a>, and if you want to agree and continue, click or tap below.`\n ),\n legalPromptAccept: \"I Agree\",\n legalPromptReject: \"Dismiss\",\n};\n\n/**\n * --- end of string definitions ---\n */\n\nconst allStrings: { [key: string]: LocalizableStrings } = {\n en_US,\n};\n\nconst localizedStrings = allStrings[cameraKitUserAgent.locale] ?? en_US;\n\nexport function localizedString<ID extends keyof LocalizableStrings>(stringId: ID): LocalizableStrings[ID] {\n return localizedStrings[stringId];\n}\n"]}
|
package/lib/common/memoize.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
type AnyFunction<A extends any[] = any[], B = any> = (...args: A) => B;
|
|
2
|
+
export type Memoized<Fn extends AnyFunction> = {
|
|
3
3
|
(...args: Parameters<Fn>): ReturnType<Fn>;
|
|
4
4
|
delegate: Fn;
|
|
5
5
|
};
|
|
@@ -21,7 +21,7 @@ function maybeInitializeVisibilityListeners() {
|
|
|
21
21
|
catch (error) {
|
|
22
22
|
// We'll do the same thing here that we would do if the handler was added directly as an event
|
|
23
23
|
// listener and dispatch an error event if we can.
|
|
24
|
-
if (typeof window
|
|
24
|
+
if (typeof window !== "undefined")
|
|
25
25
|
window.dispatchEvent(new CustomEvent("error", { detail: error }));
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageVisibility.js","sourceRoot":"","sources":["../../src/common/pageVisibility.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAc,CAAC;AAC/C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAc,CAAC;AAEhD,IAAI,uBAAuB,GAAG,QAAQ,CAAC,eAAe,CAAC;AACvD,IAAI,oBAAoB,GAAoC,KAAK,CAAC;AAElE,IAAI,WAAW,GAAG,KAAK,CAAC;AACxB,SAAS,kCAAkC;IACvC,IAAI,WAAW;QAAE,OAAO;IACxB,WAAW,GAAG,IAAI,CAAC;IAEnB,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/C,MAAM,QAAQ,GACV,uBAAuB,KAAK,SAAS,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ;YAC1E,CAAC,CAAC,gBAAgB;YAClB,CAAC,CAAC,uBAAuB,KAAK,QAAQ,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAChF,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,IAAI,GAAG,EAAc,CAAC;QAEhC,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC5B,IAAI;gBACA,OAAO,EAAE,CAAC;aACb;YAAC,OAAO,KAAK,EAAE;gBACZ,8FAA8F;gBAC9F,kDAAkD;gBAClD,IAAI,OAAO,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"pageVisibility.js","sourceRoot":"","sources":["../../src/common/pageVisibility.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAc,CAAC;AAC/C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAc,CAAC;AAEhD,IAAI,uBAAuB,GAAG,QAAQ,CAAC,eAAe,CAAC;AACvD,IAAI,oBAAoB,GAAoC,KAAK,CAAC;AAElE,IAAI,WAAW,GAAG,KAAK,CAAC;AACxB,SAAS,kCAAkC;IACvC,IAAI,WAAW;QAAE,OAAO;IACxB,WAAW,GAAG,IAAI,CAAC;IAEnB,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/C,MAAM,QAAQ,GACV,uBAAuB,KAAK,SAAS,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ;YAC1E,CAAC,CAAC,gBAAgB;YAClB,CAAC,CAAC,uBAAuB,KAAK,QAAQ,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAChF,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,IAAI,GAAG,EAAc,CAAC;QAEhC,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC5B,IAAI;gBACA,OAAO,EAAE,CAAC;aACb;YAAC,OAAO,KAAK,EAAE;gBACZ,8FAA8F;gBAC9F,kDAAkD;gBAClD,IAAI,OAAO,MAAM,KAAK,WAAW;oBAAE,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;aACxG;SACJ;QAED,uBAAuB,GAAG,oBAAoB,CAAC;QAC/C,oBAAoB,GAAG,KAAK,CAAC;IACjC,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAA6B;IACtE,OAAO,IAAI,KAAK,oBAAoB,CAAC;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC5C,kCAAkC,EAAE,CAAC;IACrC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,OAAmB;IAC7C,kCAAkC,EAAE,CAAC;IACrC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC","sourcesContent":["const onHiddenHandlers = new Set<() => void>();\nconst onVisibleHandlers = new Set<() => void>();\n\nlet previousVisibilityState = document.visibilityState;\nlet visibilityTransition: false | DocumentVisibilityState = false;\n\nlet initialized = false;\nfunction maybeInitializeVisibilityListeners(): void {\n if (initialized) return;\n initialized = true;\n\n document.addEventListener(\"visibilitychange\", () => {\n const handlers =\n previousVisibilityState === \"visible\" && document.visibilityState === \"hidden\"\n ? onHiddenHandlers\n : previousVisibilityState === \"hidden\" && document.visibilityState === \"visible\"\n ? onVisibleHandlers\n : new Set<() => void>();\n\n visibilityTransition = document.visibilityState;\n\n for (const handler of handlers) {\n try {\n handler();\n } catch (error) {\n // We'll do the same thing here that we would do if the handler was added directly as an event\n // listener and dispatch an error event if we can.\n if (typeof window !== \"undefined\") window.dispatchEvent(new CustomEvent(\"error\", { detail: error }));\n }\n }\n\n previousVisibilityState = visibilityTransition;\n visibilityTransition = false;\n });\n}\n\nexport function isDuringVisibilityTransition(test: DocumentVisibilityState): boolean {\n return test === visibilityTransition;\n}\n\n/**\n * Run a function when the page is hidden. If this occurs due to tab / browser closure, only synchronous functions will\n * run to completion.\n *\n * If the given handler throws an error, it will be silently swallowed.\n *\n * @param handler\n * @returns A function which, when called, removes the function from the set of visibility change handlers.\n */\nexport function onPageHidden(handler: () => void): () => void {\n maybeInitializeVisibilityListeners();\n onHiddenHandlers.add(handler);\n return () => onHiddenHandlers.delete(handler);\n}\n\n/**\n * Run a function when the page is made visible.\n *\n * If the given handler throws an error, it will be silently swallowed.\n *\n * @param handler\n * @returns A function which, when called, removes the function from the set of visibility change handlers.\n */\nexport function onPageVisible(handler: () => void): () => void {\n maybeInitializeVisibilityListeners();\n onVisibleHandlers.add(handler);\n return () => onVisibleHandlers.delete(handler);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
type UnknownRecord<T = unknown> = Record<string | number | symbol, T>;
|
|
2
|
+
export type Guard<T, U = unknown> = (value: U | T) => value is T;
|
|
3
3
|
export declare function isString(value: unknown): value is string;
|
|
4
4
|
/**
|
|
5
5
|
* Ensures given value is a safe string.
|
package/lib/common/types.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* For more example and use cases regarding Recursive conditional types
|
|
6
6
|
* see: https://github.com/microsoft/TypeScript/pull/40002
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
export
|
|
8
|
+
type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N ? R : _TupleOf<T, N, [T, ...R]>;
|
|
9
|
+
export type TupleOf<T, N extends number> = N extends N ? (number extends N ? T[] : _TupleOf<T, N, []>) : never;
|
|
10
10
|
export {};
|
package/lib/common/validate.js
CHANGED
|
@@ -78,27 +78,35 @@ export function isValueOfType(value, type) {
|
|
|
78
78
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#custom_method_that_gets_a_more_specific_type
|
|
79
79
|
*/
|
|
80
80
|
export function getTypeName(value) {
|
|
81
|
-
if (typeof value !== "object" && typeof value !== "function") {
|
|
82
|
-
return typeof value;
|
|
83
|
-
}
|
|
84
81
|
if (value === null) {
|
|
85
82
|
return "null";
|
|
86
83
|
}
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
const baseType = typeof value;
|
|
85
|
+
// Primitive types
|
|
86
|
+
if (!["object", "function"].includes(baseType)) {
|
|
87
|
+
return baseType;
|
|
89
88
|
}
|
|
89
|
+
// Safety: at this point null and undefined values are already handled
|
|
90
|
+
const nonNullValue = value;
|
|
90
91
|
// Symbol.toStringTag often specifies the "display name" of the
|
|
91
|
-
// object's class.
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
// object's class. It's used in Object.prototype.toString().
|
|
93
|
+
// Safety: cast to an object with Symbol.toStringTag key in order to check for its existance.
|
|
94
|
+
const tag = nonNullValue[Symbol.toStringTag];
|
|
95
|
+
if (typeof tag === "string") {
|
|
96
|
+
return tag;
|
|
97
|
+
}
|
|
98
|
+
// If it's a function whose source code starts with the "class" keyword
|
|
99
|
+
if (baseType === "function" && Function.prototype.toString.call(nonNullValue).startsWith("class")) {
|
|
100
|
+
return "class";
|
|
94
101
|
}
|
|
95
102
|
// The name of the constructor; for example `Array`, `GeneratorFunction`,
|
|
96
|
-
// `Number`, `String`, `Boolean` or `
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
// `Number`, `String`, `Boolean` or `MyCustomClass`
|
|
104
|
+
const className = nonNullValue.constructor.name;
|
|
105
|
+
if (typeof className === "string" && className !== "") {
|
|
106
|
+
return className;
|
|
99
107
|
}
|
|
100
108
|
// At this point there's no robust way to get the type of value,
|
|
101
109
|
// so we use the base implementation.
|
|
102
|
-
return
|
|
110
|
+
return baseType;
|
|
103
111
|
}
|
|
104
112
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/common/validate.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAG1B,MAAM,oBAAoB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAEhD,uCAAuC;AACvC,4BAA4B;AAC5B,sIAAsI;AACtI,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/common/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import \"reflect-metadata\";\nimport { Guard } from \"./typeguards\";\n\nconst predicateMetadataKey = Symbol(\"validate\");\n\n// A map of primitive types accoring to\n/* eslint-disable max-len */\n// http://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-4#3-basic-type-serialization_1\nconst primitiveMap: Record<string, StringConstructor | NumberConstructor | BooleanConstructor> = {\n string: String,\n number: Number,\n boolean: Boolean,\n};\n\nconst ordinalSuffixMap: Record<number, string> = {\n 1: \"st\",\n 2: \"nd\",\n 3: \"rd\",\n};\n\nfunction getArgumentInfo(target: Object, methodName: string | symbol, argumentIndex: number, arg: unknown) {\n let argString;\n try {\n argString = JSON.stringify(arg);\n } catch {\n argString = String(arg);\n }\n return {\n argPosition: `${argumentIndex + 1}${ordinalSuffixMap[argumentIndex + 1] ?? \"th\"}`,\n methodPath: `${getTypeName(target)}.${String(methodName)}()`,\n argTypeName: getTypeName(arg),\n argString,\n };\n}\n\nexport function guard<T>(predicate: Guard<T>) {\n return (target: Object, propertyKey: string | symbol, parameterIndex: number) => {\n let existingPredicates: Array<Guard<any>> =\n Reflect.getOwnMetadata(predicateMetadataKey, target, propertyKey) || [];\n existingPredicates[parameterIndex] = predicate;\n Reflect.defineMetadata(predicateMetadataKey, existingPredicates, target, propertyKey);\n };\n}\n\nexport function validate(target: Object, key: string | symbol, descriptor: PropertyDescriptor): void {\n const method = descriptor.value!;\n const types = Reflect.getMetadata(\"design:paramtypes\", target, key);\n const predicates = Reflect.getMetadata(predicateMetadataKey, target, key);\n descriptor.value = function (...args: unknown[]) {\n for (const [i, type] of types.entries()) {\n let arg = Array.isArray(args) && args[i];\n\n if (!!predicates && predicates[i] && !predicates[i](arg)) {\n const { methodPath, argPosition, argString } = getArgumentInfo(target, key, i, arg);\n throw new Error(\n `The ${argPosition} argument to ${methodPath} method has an invalid value: ${argString}.`\n );\n }\n if (arg === undefined || arg === null) {\n // TODO: is there a way to check for nullable parameter?\n break;\n }\n if (!isValueOfType(arg, type)) {\n const { methodPath, argPosition, argTypeName } = getArgumentInfo(target, key, i, arg);\n throw new Error(\n `The ${argPosition} argument to '${methodPath}' method is of type ` +\n `'${argTypeName}', which is not assignable to parameter of type '${type.name}'.`\n );\n }\n }\n return method.apply(this, arguments);\n };\n}\n\n/**\n * Checks whether given value is assignable to provided type.\n */\nexport function isValueOfType(value: unknown, type: any) {\n if (value instanceof type) {\n return true;\n }\n // test for primitive value\n const isPrimitive = value !== Object(value);\n return isPrimitive && primitiveMap[typeof value] === type;\n}\n\n/* eslint-disable max-len */\n/**\n * Returns type string of a value. It mostly mimics the behavior of typeof, but for non-primitives\n * (i.e. objects and functions), it returns a more granular type name where possible. Source:\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#custom_method_that_gets_a_more_specific_type\n */\nexport function getTypeName(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n\n const baseType = typeof value;\n // Primitive types\n if (![\"object\", \"function\"].includes(baseType)) {\n return baseType;\n }\n\n // Safety: at this point null and undefined values are already handled\n const nonNullValue = value!;\n\n // Symbol.toStringTag often specifies the \"display name\" of the\n // object's class. It's used in Object.prototype.toString().\n // Safety: cast to an object with Symbol.toStringTag key in order to check for its existance.\n const tag = (nonNullValue as { [Symbol.toStringTag]?: string })[Symbol.toStringTag];\n if (typeof tag === \"string\") {\n return tag;\n }\n\n // If it's a function whose source code starts with the \"class\" keyword\n if (baseType === \"function\" && Function.prototype.toString.call(nonNullValue).startsWith(\"class\")) {\n return \"class\";\n }\n\n // The name of the constructor; for example `Array`, `GeneratorFunction`,\n // `Number`, `String`, `Boolean` or `MyCustomClass`\n const className = nonNullValue.constructor.name;\n if (typeof className === \"string\" && className !== \"\") {\n return className;\n }\n\n // At this point there's no robust way to get the type of value,\n // so we use the base implementation.\n return baseType;\n}\n"]}
|
package/lib/configuration.d.ts
CHANGED
|
@@ -80,7 +80,7 @@ export interface CameraKitBootstrapConfiguration {
|
|
|
80
80
|
*
|
|
81
81
|
* @internal
|
|
82
82
|
*/
|
|
83
|
-
export
|
|
83
|
+
export type CameraKitConfiguration = CameraKitRuntimeConfiguration & CameraKitBootstrapConfiguration;
|
|
84
84
|
/** @internal */
|
|
85
85
|
export declare const configurationToken = "configuration";
|
|
86
86
|
/** @internal */
|
package/lib/configuration.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAU/D;;;GAGG;AACH,MAAM,oBAAoB,GAAmF;IACzG,mHAAmH;IACnH,6GAA6G;IAC7G,qFAAqF;IACrF,eAAe,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE;IAC7E,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,eAAe,EAAE,IAAI;CACxB,CAAC;AAwFF,gBAAgB;AAChB,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,gBAAgB;AAChB,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,aAA8C,EAAE,EAAE;IAClG,6DAA6D;IAC7D,MAAM,SAAS,GAAG,yBAAyB,EAAE,CAAC;IAC9C,IAAI,SAAS,EAAE;QACX,OAAO,CAAC,IAAI,CAAC,iCAAiC,EAAE,SAAS,CAAC,CAAC;KAC9D;IACD,OAAO,UAAU,
|
|
1
|
+
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAU/D;;;GAGG;AACH,MAAM,oBAAoB,GAAmF;IACzG,mHAAmH;IACnH,6GAA6G;IAC7G,qFAAqF;IACrF,eAAe,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE;IAC7E,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,eAAe,EAAE,IAAI;CACxB,CAAC;AAwFF,gBAAgB;AAChB,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,gBAAgB;AAChB,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,aAA8C,EAAE,EAAE;IAClG,6DAA6D;IAC7D,MAAM,SAAS,GAAG,yBAAyB,EAAE,CAAC;IAC9C,IAAI,SAAS,EAAE;QACX,OAAO,CAAC,IAAI,CAAC,iCAAiC,EAAE,SAAS,CAAC,CAAC;KAC9D;IACD,OAAO,UAAU,CAAC,kBAAkB,EAAE,GAA2B,EAAE;QAC/D,uGAAuG;QACvG,kFAAkF;QAClF,MAAM,UAAU,mCACT,aAAa,KAChB,eAAe,EACX,aAAa,CAAC,eAAe,YAAY,OAAO;gBAC5C,CAAC,CAAC,kFAAkF;oBAClF,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,eAAgB,CAAC;gBAClF,CAAC,CAAC,aAAa,CAAC,eAAe,GAC1C,CAAC;QACF,qDACO,oBAAoB,GACpB,qBAAqB,CAAC,UAAU,CAAC,GACjC,qBAAqB,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,EAAE,CAAC,EAC3C;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAC","sourcesContent":["import { EstimatedLensPerformance } from \"./benchmark/estimateLensPerformanceCluster\";\nimport { copyDefinedProperties } from \"./common/copyDefinedProperties\";\nimport { getConfigurationOverrides } from \"./configurationOverrides\";\nimport { Injectable } from \"./dependency-injection/Injectable\";\nimport { LogLevelName } from \"./logger/logger\";\n\n/**\n * From T, pick the set of properties whose values are optional. Create a new type containing only those properties.\n */\ntype PickOptionals<T> = {\n [K in keyof T as T[K] extends Exclude<T[K], undefined> ? never : K]: T[K];\n};\n\n/**\n * Defaults are provided for runtime configuration and any optional bootstrap configuration properties which require\n * defaults.\n */\nconst defaultConfiguration: CameraKitRuntimeConfiguration & PickOptionals<CameraKitBootstrapConfiguration> = {\n // If the applications doesn't provide performance data (e.g. via estimateLensPerformance), we'll use 0 to indicate\n // no performance estimation occurred. This is indicative of typical performance-targeting logic, which often\n // defaults to the lowest-tier experience in the absense of performance cluster data.\n lensPerformance: { cluster: 0, benchmarks: [], webglRendererInfo: \"unknown\" },\n logger: \"noop\",\n logLevel: \"info\",\n shouldUseWorker: true,\n};\n\ninterface CameraKitRuntimeConfiguration {\n lensPerformance: EstimatedLensPerformance | Promise<EstimatedLensPerformance>;\n logger: \"noop\" | \"console\";\n logLevel: LogLevelName;\n shouldUseWorker: boolean;\n}\n\n/**\n * Configuration which must be provided when calling {@link bootstrapCameraKit}. These values are used to create various\n * CameraKit components.\n *\n * @category Bootstrapping and Configuration\n */\nexport interface CameraKitBootstrapConfiguration {\n /**\n * Long-lived token granting your application access to CameraKit APIs. This is found in the SnapKit Dev Portal,\n * where it's called the API Token.\n */\n apiToken: string;\n\n /**\n * Determine where to print CameraKit log messages. By default no logs will be printed.\n *\n * CameraKit emits log messages to help diagnose and root cause issues that may occur during the development of a\n * host application. The printing of these can be controlled via the following\n * options:\n * - `noop`: log messages are ignored.\n * - `console`: log messages are printed to console.\n */\n logger?: \"noop\" | \"console\";\n\n /**\n * Log only if a logged entry level is greater than or equal to this level. Here is the order of levels:\n * error > warn > log = info > debug. Default value is \"info\".\n */\n logLevel?: LogLevelName;\n\n /**\n * Some lenses may decide to modify their behavior based on the performance of the current environment. If you are\n * using such lenses, providing an estimation of lens performance may lead to better user experience (especially on\n * low-performance devices).\n *\n * Running the {@link estimateLensPerformance} function will run benchmarks and estimate an appropriate lens\n * performance cluster (i.e. a performance rating) based on the current environment.\n *\n * Lower cluster = worse expected performance capability.\n *\n * @example\n * ```ts\n * import { bootstrapCameraKit, estimateLensPerformance } from '@snap/camera-kit`\n *\n * const cameraKit = await bootstrapCameraKit({\n * apiToken: '...',\n * lensPerformance: estimateLensPerformance(),\n * })\n * ```\n */\n lensPerformance?: EstimatedLensPerformance | Promise<EstimatedLensPerformance>;\n\n /**\n * In recommended production deployments, the WebAssembly assets required by CameraKit will be downloaded from an\n * optimized CDN. But sometimes (e.g. during development or within a CI pipeline), it may be necessary to download\n * these assets from somewhere else.\n *\n * This configuration option allows the application to specify URLs to be used for both the WebAssembly and JS glue\n * file that are used to run and interact with CameraKit's rendering engine.\n */\n lensCoreOverrideUrls?: { wasm: string; js: string };\n\n /**\n * In recommended production deployments, the WebAssembly assets required by CameraKit will be downloaded from an\n * optimized CDN. But sometimes during development or within a CI pipeline, it may be necessary to download these\n * assets from somewhere else. With a provided `wasmEndpointOverride`, asset URLs will be automatically generated\n * based on this root endpoint.\n */\n wasmEndpointOverride?: string;\n}\n\n/**\n * This type represents the result of merging user-supplied config with default config -- as such, it has no nullable\n * fields, making it a more convenient type for other components to use.\n *\n * @internal\n */\nexport type CameraKitConfiguration = CameraKitRuntimeConfiguration & CameraKitBootstrapConfiguration;\n\n/** @internal */\nexport const configurationToken = \"configuration\";\n\n/** @internal */\nexport const createCameraKitConfigurationFactory = (configuration: CameraKitBootstrapConfiguration) => {\n // always leave debug mode warning about overrides in console\n const overrides = getConfigurationOverrides();\n if (overrides) {\n console.warn(\"Configuration overrides applied\", overrides);\n }\n return Injectable(configurationToken, (): CameraKitConfiguration => {\n // We'll ensure that we handle errors on any Promises passed as config values, otherwise we either must\n // handle them separately wherever they're used, or rejections would go unhandled.\n const safeConfig: CameraKitBootstrapConfiguration = {\n ...configuration,\n lensPerformance:\n configuration.lensPerformance instanceof Promise\n ? // Safety: defaultConfiguration.lensPerformance is defined (it's hardcoded above).\n configuration.lensPerformance.catch(() => defaultConfiguration.lensPerformance!)\n : configuration.lensPerformance,\n };\n return {\n ...defaultConfiguration,\n ...copyDefinedProperties(safeConfig),\n ...copyDefinedProperties(overrides ?? {}),\n };\n });\n};\n"]}
|
|
@@ -2,7 +2,7 @@ import { CameraKitBootstrapConfiguration } from "./configuration";
|
|
|
2
2
|
/**
|
|
3
3
|
* Configuration overrides that are stored in session storage.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
type StoredOverrides = Pick<CameraKitBootstrapConfiguration, "wasmEndpointOverride" | "logger" | "logLevel">;
|
|
6
6
|
/**
|
|
7
7
|
* Checks whether there are configuration overrides stored, and if yes, returns them.
|
|
8
8
|
*
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { Memoized } from "../common/memoize";
|
|
2
2
|
import { PartialContainer } from "./PartialContainer";
|
|
3
3
|
import { AddService, InjectableFunction, ValidTokens } from "./types";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[K in keyof Services]: ((c: UnsafePartialContainer<Services>) => Services[K]) | Memoized<(c: UnsafePartialContainer<Services>) => Services[K]>;
|
|
4
|
+
type MaybeMemoizedFactories<Services> = {
|
|
5
|
+
[K in keyof Services]: ((c: Container<Services>) => Services[K]) | Memoized<(c: Container<Services>) => Services[K]>;
|
|
7
6
|
};
|
|
8
|
-
export
|
|
9
|
-
[K in keyof Services]: Memoized<(c:
|
|
7
|
+
export type Factories<Services> = {
|
|
8
|
+
[K in keyof Services]: Memoized<(c: Container<Services>) => Services[K]>;
|
|
10
9
|
};
|
|
11
10
|
export declare const CONTAINER = "$container";
|
|
12
|
-
export
|
|
11
|
+
export type ContainerToken = typeof CONTAINER;
|
|
13
12
|
/**
|
|
14
13
|
* A Container of values, indexed each by a unique token, which can be used throughout CameraKit. This is how CameraKit
|
|
15
14
|
* implements simple dependency injection.
|
|
@@ -105,7 +105,7 @@ export class Container {
|
|
|
105
105
|
return this;
|
|
106
106
|
const factory = this.factories[token];
|
|
107
107
|
if (!factory) {
|
|
108
|
-
throw new Error(`[Container::get] Could not find Service for Token "${token}". This should've caused a ` +
|
|
108
|
+
throw new Error(`[Container::get] Could not find Service for Token "${String(token)}". This should've caused a ` +
|
|
109
109
|
"compile-time error. If the Token is 'undefined', check all your calls to the Injectable " +
|
|
110
110
|
"function. Make sure you define dependencies using string literals or string constants that are " +
|
|
111
111
|
"definitely initialized before the call to Injectable.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/dependency-injection/Container.ts"],"names":[],"mappings":"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","sourcesContent":["import { isMemoized, memoize, Memoized } from \"../common/memoize\";\nimport { PartialContainer } from \"./PartialContainer\";\nimport { AddService, InjectableFunction, ValidTokens } from \"./types\";\n\n// This is un-safe. In practice, Containers should always be created by calling `Container::provides` on some other\n// Container (except for some \"root\" Container which is instantiated with no Services) – `Container::provides\" is safely\n// type-checked, so this doesn't introduce much risk. But a more accurate solution would be for the `Factories` and\n// `MaybeMemoizedFactories` types to keep track of which specific Services must be present in the Container\n// corresponding to each Service. But this is much more complex to implement.\ntype UnsafePartialContainer<Services> = Container<Partial<Services>>;\n\ntype MaybeMemoizedFactories<Services> = {\n [K in keyof Services]:\n | ((c: UnsafePartialContainer<Services>) => Services[K])\n | Memoized<(c: UnsafePartialContainer<Services>) => Services[K]>;\n};\n\nexport type Factories<Services> = {\n [K in keyof Services]: Memoized<(c: UnsafePartialContainer<Services>) => Services[K]>;\n};\n\nexport const CONTAINER = \"$container\";\nexport type ContainerToken = typeof CONTAINER;\n\n/**\n * A Container of values, indexed each by a unique token, which can be used throughout CameraKit. This is how CameraKit\n * implements simple dependency injection.\n *\n * Dependency injection is a way to decouple the *use* of a dependency from the *creation* of that dependency. This\n * improves modularity and re-usability, since components only care about the *interfaces* of dependencies (since that\n * determines their use) and not about their concrete creation. New implementations of a particular dependency may be\n * provided without the need to change any of the consumers of that dependency.\n *\n * There are a few commonly-used terms used when talking about dependency injection:\n *\n * - Container (or Injector): Maintains a registry of all available Services and understands how to create them.\n * - Service: Anything that can be provided by the Container is called a Service – this can be a value of any type.\n * - Token: Each Service is associated with a unique name, or Token. In order to obtain a Service from the Container,\n * the consumer must provide the Token corresponding to that Service.\n * - InjectableFunction: Services are created by InjectableFunctions. When adding a Service to a Container, the\n * Service provider gives the Container a InjectableFunction which, when called will return the Service. These\n * InjectableFunctions may themselves use other Services, which will be passed to them as arguments.\n *\n * Services are, by default, singletons – that is, each call to `get()` a particular Service will return a reference\n * to the same value. In other words, InjectableFunctions are only invoked once. If multiple instances of a Service are\n * desired, a new Container can be created using the `copy([Token])` method – passing a Token to this method forces the\n * new Container to recreate the corresponding Service (the InjectableFunction will be invoked again). We say that the\n * Service is then \"scoped\" to the new Container.\n *\n *\n * One common downside of many dependency injection implementations is that the dependency graph formed by the various\n * Services can only be validated at runtime. That is, if a dependency is missing or a circular dependency is found, the\n * developer must wait until runtime to discover the error. These errors can often be confusing and hard to debug.\n *\n * This implementation eliminates this issue by moving these sorts of errors to compile time. If an unknown dependency\n * is used in a InjectableFunction, for example, the code simply won't compile.\n *\n * To achieve this, we do lose the ability to implicitly define the dependency graph, as is common with many dependency\n * injection frameworks that employ decorators to define Services and their dependencies. Instead, the dependency graph\n * must be constructed explicitly, step-by-step, via successive calls to the `provide()` method. This is a suitable\n * trade-off for CameraKit, as there are a relatively small number of Services.\n *\n * Here's a simple example of Container usage:\n * ```ts\n * const fooFactory = Injectable('Foo', () => new Foo())\n * const barFactory = Injectable('Bar', ['Foo'] as const, (foo: Foo) => new Bar(foo))\n * const container = Container.empy()\n * .provide(fooFactory)\n * .provide(barFactory)\n *\n * const bar: Bar = container.get('Bar')\n * ```\n */\n/** @internal */\nexport class Container<Services = {}> {\n private readonly factories: Factories<Services>;\n\n constructor(factories: MaybeMemoizedFactories<Services>) {\n this.factories = {} as Factories<Services>;\n for (const k in factories) {\n const fn = factories[k];\n if (isMemoized(fn)) this.factories[k] = fn;\n else this.factories[k] = memoize(fn);\n }\n }\n\n /**\n * Create a new [Container] by providing a [PartialContainer] that has no dependencies.\n */\n static provides<Services>(container: PartialContainer<Services, {}> | Container<Services>): Container<Services>;\n\n /**\n * Create a new [Container] by providing a Service that has no dependencies.\n */\n static provides<Token extends string, Service>(\n fn: InjectableFunction<{}, [], Token, Service>\n ): Container<AddService<{}, Token, Service>>;\n\n static provides(\n fnOrContainer: InjectableFunction<{}, [], string, any> | PartialContainer<any, {}> | Container<any>\n ): Container<any> {\n // Although the `provides` method has overloads that match both members of the union type separately, it does\n // not match the union type itself, so the compiler forces us to branch and handle each type within the union\n // separately. (Maybe in the future the compiler will decide to infer this, but for now this is necessary.)\n if (fnOrContainer instanceof PartialContainer) return new Container({}).provides(fnOrContainer);\n if (fnOrContainer instanceof Container) return new Container({}).provides(fnOrContainer);\n return new Container({}).provides(fnOrContainer);\n }\n\n /**\n * Create a copy of this Container, optionally providing a list of Services which will be scoped to the copy.\n *\n * This can be useful, for example, if different parts of an application wish to use the same Service interface, but\n * do not want to share a reference to same Service instance.\n *\n * Say we have a Service which manages a list of Users. Our application wishes to display two lists of Users, which\n * may be edited independently. In this case it may be desirable to create a Container for each list component, with\n * the UserList Service scoped to those Containers – that way, each list component gets a unique copy of the\n * UserList Service that can be edited independently of the other.\n *\n * @param scopedServices A list of Tokens identifying Services which will be scoped to the new Container – that is,\n * if those Services had already been created by the source Container, they will be re-created by their Factory\n * functions when provided by the new Container.\n * @returns A new copy of this Container, sharing all of this Container's Services. Services corresponding to any\n * Tokens passed to this method will be re-created by the new Container (i.e. they become \"scoped\" to the new\n * Container).\n */\n copy<Tokens extends readonly (keyof Services)[]>(scopedServices?: Tokens): Container<Services> {\n const factories: MaybeMemoizedFactories<Services> = { ...this.factories };\n\n // We \"un-memoize\" scoped Service InjectableFunctions so they will create a new copy of their Service when\n // provided by the new Container – we re-memoize them so the new Container will itself only create one Service\n // instance.\n (scopedServices || []).forEach((token: keyof Services) => {\n factories[token] = this.factories[token].delegate;\n });\n return new Container(factories);\n }\n\n /**\n * Gets a reference to this Container.\n *\n * @param token The CONTAINER token.\n * @returns This Container.\n */\n get(token: ContainerToken): this;\n\n /**\n * Get a specific Service provided by this Container.\n *\n * @param token A unique string corresponding to a Service\n * @returns A Service corresponding to the given Token.\n */\n get<Token extends keyof Services>(token: Token): Services[Token];\n\n get(token: string): this | Services[keyof Services] {\n if (token === CONTAINER) return this;\n const factory = this.factories[token];\n if (!factory) {\n throw new Error(\n `[Container::get] Could not find Service for Token \"${token}\". This should've caused a ` +\n \"compile-time error. If the Token is 'undefined', check all your calls to the Injectable \" +\n \"function. Make sure you define dependencies using string literals or string constants that are \" +\n \"definitely initialized before the call to Injectable.\"\n );\n }\n return factory(this);\n }\n\n /**\n * Run the services in this [PartialContainer]. \"Run\" simply means that [Container::get] will be called for each\n * Service, which invokes that Service's factory function, creating the Service.\n *\n * This may be useful e.g. if services need to initialize themselves, since generally a Service factory is only\n * invoked when the Service is needed.\n *\n * Note this method cannot be used to add services to a Container. – that is, calling this method does not provide\n * the services in a new Container.\n *\n * @param container Optionally provide a [PartialContainer], which will be used as a filter – the only services\n * from *this* container that will run are those with a token that is also present in this PartialContainer.\n * @returns No mutation is done to the Container, it is returned as-is (convenient for chaining).\n */\n run<AdditionalServices, Dependencies, FulfilledDependencies extends Dependencies>(\n // FullfilledDependencies is assignable to Dependencies -- by specifying Container<FulfilledDependencies> as the\n // `this` type, we ensure this Container can provide all the Dependencies required by the PartialContainer.\n this: Container<FulfilledDependencies>,\n container: PartialContainer<AdditionalServices, Dependencies>\n ): this;\n\n /**\n * Run the given Service. \"Run\" simply means that [Container::get] will be called for this Service, which invokes\n * the Service's factory function, creating the Service.\n *\n * This may be useful e.g. if services need to initialize themselves, since generally a Service factory is only\n * invoked when the Service is needed.\n *\n * Note this method cannot be used to add services to a Container. – that is, calling this method does not provide\n * the services in a new Container.\n *\n * @param fn Optionally provide an [InjectableFunction], which will be used as a filter – the only services\n * from *this* container that will run are those with a token that is also present in this PartialContainer.\n * @returns No mutation is done to the Container, it is returned as-is (convenient for chaining).\n */\n run<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): this;\n\n run<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service, AdditionalServices>(\n fnOrContainer:\n | InjectableFunction<Services, Tokens, Token, Service>\n | PartialContainer<AdditionalServices, Services>\n ): this {\n if (fnOrContainer instanceof PartialContainer) {\n const runnableContainer = this.provides(fnOrContainer);\n for (const token of fnOrContainer.getTokens()) {\n runnableContainer.get(token);\n }\n } else {\n this.provides(fnOrContainer).get(fnOrContainer.token);\n }\n return this;\n }\n\n /**\n * Create a new Container from this Container with additional services from a given [PartialContainer].\n *\n * Services in the provided PartialContainer take precedence if there are service token conflicts.\n *\n * Services from the provided PartialContainer become scoped to the new Container – that is, if PartialContainer A\n * is provided to Container X and Container Y, each resultant Container will contain its own copy of the services\n * from PartialContainer A.\n *\n * @param container A [PartialContainer] providing additional services.\n */\n provides<AdditionalServices, Dependencies, FulfilledDependencies extends Dependencies>(\n // FullfilledDependencies is assignable to Dependencies -- by specifying Container<FulfilledDependencies> as the\n // `this` type, we ensure this Container can provide all the Dependencies required by the PartialContainer.\n this: Container<FulfilledDependencies>,\n container: PartialContainer<AdditionalServices, Dependencies>\n ): Container<Services & AdditionalServices>;\n\n /**\n * Creates a new Container from this Container with additional services from another Container.\n *\n * Services in the provided PartialContainer take precedence if there are service token conflicts.\n *\n * Services from the provided Container become scoped to both Containers (the one from which they were provided\n * and the new Container returned by this method) - that is, if Container A is provided to Container B,\n * they will share the same instances of any Services provided by Container A.\n * If Container B should re-create new instances of the Services from Container A,\n * Container A must first be copied before providing it here.\n *\n * @param container A [Container] providing additional services.\n */\n provides<AdditionalServices>(container: Container<AdditionalServices>): Container<Services & AdditionalServices>;\n\n /**\n * Create a new Container which provides a Service created by the given [InjectableFunction].\n *\n * The InjectableFunction contains metadata specifying the Token by which the created Service will be known, as well\n * as an ordered list of Tokens to be resolved and provided to the InjectableFunction as arguments.\n *\n * If any of these required dependencies are missing from the Container (or if there is a mismatch between the types\n * of those dependencies and the arguments of the InjectableFunction), a compiler error will be raised.\n *\n * @param fn A factory function, taking dependencies as arguments, which returns the Service.\n */\n provides<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): Container<AddService<Services, Token, Service>>;\n\n provides<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service, AdditionalServices>(\n fnOrContainer:\n | InjectableFunction<Services, Tokens, Token, Service>\n | PartialContainer<AdditionalServices, Services>\n | Container<AdditionalServices>\n ): Container<any> {\n if (fnOrContainer instanceof PartialContainer || fnOrContainer instanceof Container) {\n const factories =\n fnOrContainer instanceof PartialContainer ? fnOrContainer.getFactories(this) : fnOrContainer.factories;\n // Safety: `this.factories` and `factories` are both properly type checked, so merging them produces\n // a Factories object with keys from both Services and AdditionalServices. The compiler is unable to\n // infer that Factories<A> & Factories<B> == Factories<A & B>, so the cast is required.\n return new Container(({\n ...this.factories,\n ...factories,\n } as unknown) as MaybeMemoizedFactories<Services & AdditionalServices>);\n }\n return this.providesService(fnOrContainer);\n }\n\n private providesService<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): Container<AddService<Services, Token, Service>> {\n const token = fn.token;\n const dependencies: readonly any[] = fn.dependencies;\n\n const factory = memoize((container: Container<Services>) => {\n return fn(\n ...(dependencies.map((t) => {\n // To support overwriting an already-existing service with a new implementation, it should be\n // possibleto do `provide(A, [A], a => createNewServiceFromOld(a))` – that is, inject a dependency\n // with the same token as this service's token.\n //\n // To avoid a circular dependency (in which the factory for service A depends on itself), we always\n // use the service defined in the *parent* container (i.e. this) when injecting a dependency with\n // the same token as the service we're providing. If we did not do this, calling `container.get(t)`\n // would result in an infinite loop.\n return t === token ? this.get(t) : container.get(t);\n }) as any)\n );\n });\n\n // Safety: `token` and `factory` are property type checked, so extending `this.factories` produces a\n // MaybeMemoizedFactories object with the expected set of services – but when using the spread operation to\n // merge two objects, the compiler widens the Token type to string. So we must re-narrow via casting.\n const factories = { ...this.factories, [token]: factory };\n return new Container((factories as unknown) as MaybeMemoizedFactories<AddService<Services, Token, Service>>);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/dependency-injection/Container.ts"],"names":[],"mappings":"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","sourcesContent":["import { isMemoized, memoize, Memoized } from \"../common/memoize\";\nimport { PartialContainer } from \"./PartialContainer\";\nimport { AddService, InjectableFunction, ValidTokens } from \"./types\";\n\ntype MaybeMemoizedFactories<Services> = {\n [K in keyof Services]:\n | ((c: Container<Services>) => Services[K])\n | Memoized<(c: Container<Services>) => Services[K]>;\n};\n\nexport type Factories<Services> = {\n [K in keyof Services]: Memoized<(c: Container<Services>) => Services[K]>;\n};\n\nexport const CONTAINER = \"$container\";\nexport type ContainerToken = typeof CONTAINER;\n\n/**\n * A Container of values, indexed each by a unique token, which can be used throughout CameraKit. This is how CameraKit\n * implements simple dependency injection.\n *\n * Dependency injection is a way to decouple the *use* of a dependency from the *creation* of that dependency. This\n * improves modularity and re-usability, since components only care about the *interfaces* of dependencies (since that\n * determines their use) and not about their concrete creation. New implementations of a particular dependency may be\n * provided without the need to change any of the consumers of that dependency.\n *\n * There are a few commonly-used terms used when talking about dependency injection:\n *\n * - Container (or Injector): Maintains a registry of all available Services and understands how to create them.\n * - Service: Anything that can be provided by the Container is called a Service – this can be a value of any type.\n * - Token: Each Service is associated with a unique name, or Token. In order to obtain a Service from the Container,\n * the consumer must provide the Token corresponding to that Service.\n * - InjectableFunction: Services are created by InjectableFunctions. When adding a Service to a Container, the\n * Service provider gives the Container a InjectableFunction which, when called will return the Service. These\n * InjectableFunctions may themselves use other Services, which will be passed to them as arguments.\n *\n * Services are, by default, singletons – that is, each call to `get()` a particular Service will return a reference\n * to the same value. In other words, InjectableFunctions are only invoked once. If multiple instances of a Service are\n * desired, a new Container can be created using the `copy([Token])` method – passing a Token to this method forces the\n * new Container to recreate the corresponding Service (the InjectableFunction will be invoked again). We say that the\n * Service is then \"scoped\" to the new Container.\n *\n *\n * One common downside of many dependency injection implementations is that the dependency graph formed by the various\n * Services can only be validated at runtime. That is, if a dependency is missing or a circular dependency is found, the\n * developer must wait until runtime to discover the error. These errors can often be confusing and hard to debug.\n *\n * This implementation eliminates this issue by moving these sorts of errors to compile time. If an unknown dependency\n * is used in a InjectableFunction, for example, the code simply won't compile.\n *\n * To achieve this, we do lose the ability to implicitly define the dependency graph, as is common with many dependency\n * injection frameworks that employ decorators to define Services and their dependencies. Instead, the dependency graph\n * must be constructed explicitly, step-by-step, via successive calls to the `provide()` method. This is a suitable\n * trade-off for CameraKit, as there are a relatively small number of Services.\n *\n * Here's a simple example of Container usage:\n * ```ts\n * const fooFactory = Injectable('Foo', () => new Foo())\n * const barFactory = Injectable('Bar', ['Foo'] as const, (foo: Foo) => new Bar(foo))\n * const container = Container.empy()\n * .provide(fooFactory)\n * .provide(barFactory)\n *\n * const bar: Bar = container.get('Bar')\n * ```\n */\n/** @internal */\nexport class Container<Services = {}> {\n private readonly factories: Factories<Services>;\n\n constructor(factories: MaybeMemoizedFactories<Services>) {\n this.factories = {} as Factories<Services>;\n for (const k in factories) {\n const fn = factories[k];\n if (isMemoized(fn)) this.factories[k] = fn;\n else this.factories[k] = memoize(fn);\n }\n }\n\n /**\n * Create a new [Container] by providing a [PartialContainer] that has no dependencies.\n */\n static provides<Services>(container: PartialContainer<Services, {}> | Container<Services>): Container<Services>;\n\n /**\n * Create a new [Container] by providing a Service that has no dependencies.\n */\n static provides<Token extends string, Service>(\n fn: InjectableFunction<{}, [], Token, Service>\n ): Container<AddService<{}, Token, Service>>;\n\n static provides(\n fnOrContainer: InjectableFunction<{}, [], string, any> | PartialContainer<any, {}> | Container<any>\n ): Container<any> {\n // Although the `provides` method has overloads that match both members of the union type separately, it does\n // not match the union type itself, so the compiler forces us to branch and handle each type within the union\n // separately. (Maybe in the future the compiler will decide to infer this, but for now this is necessary.)\n if (fnOrContainer instanceof PartialContainer) return new Container({}).provides(fnOrContainer);\n if (fnOrContainer instanceof Container) return new Container({}).provides(fnOrContainer);\n return new Container({}).provides(fnOrContainer);\n }\n\n /**\n * Create a copy of this Container, optionally providing a list of Services which will be scoped to the copy.\n *\n * This can be useful, for example, if different parts of an application wish to use the same Service interface, but\n * do not want to share a reference to same Service instance.\n *\n * Say we have a Service which manages a list of Users. Our application wishes to display two lists of Users, which\n * may be edited independently. In this case it may be desirable to create a Container for each list component, with\n * the UserList Service scoped to those Containers – that way, each list component gets a unique copy of the\n * UserList Service that can be edited independently of the other.\n *\n * @param scopedServices A list of Tokens identifying Services which will be scoped to the new Container – that is,\n * if those Services had already been created by the source Container, they will be re-created by their Factory\n * functions when provided by the new Container.\n * @returns A new copy of this Container, sharing all of this Container's Services. Services corresponding to any\n * Tokens passed to this method will be re-created by the new Container (i.e. they become \"scoped\" to the new\n * Container).\n */\n copy<Tokens extends readonly (keyof Services)[]>(scopedServices?: Tokens): Container<Services> {\n const factories: MaybeMemoizedFactories<Services> = { ...this.factories };\n\n // We \"un-memoize\" scoped Service InjectableFunctions so they will create a new copy of their Service when\n // provided by the new Container – we re-memoize them so the new Container will itself only create one Service\n // instance.\n (scopedServices || []).forEach((token: keyof Services) => {\n factories[token] = this.factories[token].delegate;\n });\n return new Container(factories);\n }\n\n /**\n * Gets a reference to this Container.\n *\n * @param token The CONTAINER token.\n * @returns This Container.\n */\n get(token: ContainerToken): this;\n\n /**\n * Get a specific Service provided by this Container.\n *\n * @param token A unique string corresponding to a Service\n * @returns A Service corresponding to the given Token.\n */\n get<Token extends keyof Services>(token: Token): Services[Token];\n\n get(token: ContainerToken | keyof Services): this | Services[keyof Services] {\n if (token === CONTAINER) return this;\n const factory = this.factories[token];\n if (!factory) {\n throw new Error(\n `[Container::get] Could not find Service for Token \"${String(token)}\". This should've caused a ` +\n \"compile-time error. If the Token is 'undefined', check all your calls to the Injectable \" +\n \"function. Make sure you define dependencies using string literals or string constants that are \" +\n \"definitely initialized before the call to Injectable.\"\n );\n }\n return factory(this);\n }\n\n /**\n * Run the services in this [PartialContainer]. \"Run\" simply means that [Container::get] will be called for each\n * Service, which invokes that Service's factory function, creating the Service.\n *\n * This may be useful e.g. if services need to initialize themselves, since generally a Service factory is only\n * invoked when the Service is needed.\n *\n * Note this method cannot be used to add services to a Container. – that is, calling this method does not provide\n * the services in a new Container.\n *\n * @param container Optionally provide a [PartialContainer], which will be used as a filter – the only services\n * from *this* container that will run are those with a token that is also present in this PartialContainer.\n * @returns No mutation is done to the Container, it is returned as-is (convenient for chaining).\n */\n run<AdditionalServices, Dependencies, FulfilledDependencies extends Dependencies>(\n // FullfilledDependencies is assignable to Dependencies -- by specifying Container<FulfilledDependencies> as the\n // `this` type, we ensure this Container can provide all the Dependencies required by the PartialContainer.\n this: Container<FulfilledDependencies>,\n container: PartialContainer<AdditionalServices, Dependencies>\n ): this;\n\n /**\n * Run the given Service. \"Run\" simply means that [Container::get] will be called for this Service, which invokes\n * the Service's factory function, creating the Service.\n *\n * This may be useful e.g. if services need to initialize themselves, since generally a Service factory is only\n * invoked when the Service is needed.\n *\n * Note this method cannot be used to add services to a Container. – that is, calling this method does not provide\n * the services in a new Container.\n *\n * @param fn Optionally provide an [InjectableFunction], which will be used as a filter – the only services\n * from *this* container that will run are those with a token that is also present in this PartialContainer.\n * @returns No mutation is done to the Container, it is returned as-is (convenient for chaining).\n */\n run<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): this;\n\n run<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service, AdditionalServices>(\n fnOrContainer:\n | InjectableFunction<Services, Tokens, Token, Service>\n | PartialContainer<AdditionalServices, Services>\n ): this {\n if (fnOrContainer instanceof PartialContainer) {\n const runnableContainer = this.provides(fnOrContainer);\n for (const token of fnOrContainer.getTokens()) {\n runnableContainer.get(token);\n }\n } else {\n this.provides(fnOrContainer).get(fnOrContainer.token);\n }\n return this;\n }\n\n /**\n * Create a new Container from this Container with additional services from a given [PartialContainer].\n *\n * Services in the provided PartialContainer take precedence if there are service token conflicts.\n *\n * Services from the provided PartialContainer become scoped to the new Container – that is, if PartialContainer A\n * is provided to Container X and Container Y, each resultant Container will contain its own copy of the services\n * from PartialContainer A.\n *\n * @param container A [PartialContainer] providing additional services.\n */\n provides<AdditionalServices, Dependencies, FulfilledDependencies extends Dependencies>(\n // FullfilledDependencies is assignable to Dependencies -- by specifying Container<FulfilledDependencies> as the\n // `this` type, we ensure this Container can provide all the Dependencies required by the PartialContainer.\n this: Container<FulfilledDependencies>,\n container: PartialContainer<AdditionalServices, Dependencies>\n ): Container<Services & AdditionalServices>;\n\n /**\n * Creates a new Container from this Container with additional services from another Container.\n *\n * Services in the provided PartialContainer take precedence if there are service token conflicts.\n *\n * Services from the provided Container become scoped to both Containers (the one from which they were provided\n * and the new Container returned by this method) - that is, if Container A is provided to Container B,\n * they will share the same instances of any Services provided by Container A.\n * If Container B should re-create new instances of the Services from Container A,\n * Container A must first be copied before providing it here.\n *\n * @param container A [Container] providing additional services.\n */\n provides<AdditionalServices>(container: Container<AdditionalServices>): Container<Services & AdditionalServices>;\n\n /**\n * Create a new Container which provides a Service created by the given [InjectableFunction].\n *\n * The InjectableFunction contains metadata specifying the Token by which the created Service will be known, as well\n * as an ordered list of Tokens to be resolved and provided to the InjectableFunction as arguments.\n *\n * If any of these required dependencies are missing from the Container (or if there is a mismatch between the types\n * of those dependencies and the arguments of the InjectableFunction), a compiler error will be raised.\n *\n * @param fn A factory function, taking dependencies as arguments, which returns the Service.\n */\n provides<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): Container<AddService<Services, Token, Service>>;\n\n provides<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service, AdditionalServices>(\n fnOrContainer:\n | InjectableFunction<Services, Tokens, Token, Service>\n | PartialContainer<AdditionalServices, Services>\n | Container<AdditionalServices>\n ): Container<any> {\n if (fnOrContainer instanceof PartialContainer || fnOrContainer instanceof Container) {\n const factories =\n fnOrContainer instanceof PartialContainer ? fnOrContainer.getFactories(this) : fnOrContainer.factories;\n // Safety: `this.factories` and `factories` are both properly type checked, so merging them produces\n // a Factories object with keys from both Services and AdditionalServices. The compiler is unable to\n // infer that Factories<A> & Factories<B> == Factories<A & B>, so the cast is required.\n return new Container({\n ...this.factories,\n ...factories,\n } as unknown as MaybeMemoizedFactories<Services & AdditionalServices>);\n }\n return this.providesService(fnOrContainer);\n }\n\n private providesService<Token extends string, Tokens extends readonly ValidTokens<Services>[], Service>(\n fn: InjectableFunction<Services, Tokens, Token, Service>\n ): Container<AddService<Services, Token, Service>> {\n const token = fn.token;\n const dependencies: readonly any[] = fn.dependencies;\n\n const factory = memoize((container: Container<Services>) => {\n return fn(\n ...(dependencies.map((t) => {\n // To support overwriting an already-existing service with a new implementation, it should be\n // possibleto do `provide(A, [A], a => createNewServiceFromOld(a))` – that is, inject a dependency\n // with the same token as this service's token.\n //\n // To avoid a circular dependency (in which the factory for service A depends on itself), we always\n // use the service defined in the *parent* container (i.e. this) when injecting a dependency with\n // the same token as the service we're providing. If we did not do this, calling `container.get(t)`\n // would result in an infinite loop.\n return t === token ? this.get(t) : container.get(t);\n }) as any)\n );\n });\n\n // Safety: `token` and `factory` are property type checked, so extending `this.factories` produces a\n // MaybeMemoizedFactories object with the expected set of services – but when using the spread operation to\n // merge two objects, the compiler widens the Token type to string. So we must re-narrow via casting.\n const factories = { ...this.factories, [token]: factory };\n return new Container(factories as unknown as MaybeMemoizedFactories<AddService<Services, Token, Service>>);\n }\n}\n"]}
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Memoized } from "../common/memoize";
|
|
2
|
+
import { Container } from "./Container";
|
|
2
3
|
import { AddService, InjectableFunction, ServicesFromTokenizedParams, ValidTokens } from "./types";
|
|
3
|
-
|
|
4
|
+
type AddDependencies<ParentDependencies, Dependencies> = ParentDependencies extends any ? {
|
|
4
5
|
[K in keyof ParentDependencies | keyof Dependencies]: K extends keyof ParentDependencies ? ParentDependencies[K] : K extends keyof Dependencies ? Dependencies[K] : never;
|
|
5
6
|
} : never;
|
|
6
|
-
|
|
7
|
+
type ExcludeKey<T, U> = T extends any ? {
|
|
7
8
|
[K in Exclude<keyof T, U>]: T[K];
|
|
8
9
|
} : never;
|
|
9
|
-
|
|
10
|
+
type PartialInjectableFunction<Params extends readonly any[], Tokens extends readonly string[], Token extends string, Service> = {
|
|
10
11
|
(...args: Params): Service;
|
|
11
12
|
token: Token;
|
|
12
13
|
dependencies: Tokens;
|
|
13
14
|
};
|
|
14
|
-
|
|
15
|
+
type Injectables<Services, Dependencies> = {
|
|
15
16
|
[K in keyof Services]: K extends string ? InjectableFunction<Services & Dependencies, readonly ValidTokens<Services & Dependencies>[], K, Services[K]> : never;
|
|
16
17
|
};
|
|
18
|
+
type PartialContainerFactories<Services, Dependecies> = {
|
|
19
|
+
[K in keyof Services]: Memoized<(c: Container<Partial<Services> & Dependecies>) => Services[K]>;
|
|
20
|
+
};
|
|
17
21
|
/**
|
|
18
22
|
* Similar to [Container], with the exception that Services may be provided to a PartialContainer which *does not*
|
|
19
23
|
* contain all of that Services dependencies.
|
|
@@ -75,7 +79,7 @@ export declare class PartialContainer<Services = {}, Dependencies = {}> {
|
|
|
75
79
|
*
|
|
76
80
|
* @param parent A [Container] which provides all the required Dependencies of this PartialContainer.
|
|
77
81
|
*/
|
|
78
|
-
getFactories(parent: Container<Dependencies>):
|
|
82
|
+
getFactories(parent: Container<Dependencies>): PartialContainerFactories<Services, Dependencies>;
|
|
79
83
|
getTokens(): Array<keyof Services>;
|
|
80
84
|
}
|
|
81
85
|
export {};
|