@snap/react-camera-kit 0.0.1

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.
Files changed (132) hide show
  1. package/LICENSE.md +37 -0
  2. package/README.md +130 -0
  3. package/dist/cjs/CameraKitProvider.d.ts +203 -0
  4. package/dist/cjs/CameraKitProvider.d.ts.map +1 -0
  5. package/dist/cjs/CameraKitProvider.js +542 -0
  6. package/dist/cjs/CameraKitProvider.js.map +1 -0
  7. package/dist/cjs/Canvas.d.ts +7 -0
  8. package/dist/cjs/Canvas.d.ts.map +1 -0
  9. package/dist/cjs/Canvas.js +50 -0
  10. package/dist/cjs/Canvas.js.map +1 -0
  11. package/dist/cjs/LensPlayer.d.ts +101 -0
  12. package/dist/cjs/LensPlayer.d.ts.map +1 -0
  13. package/dist/cjs/LensPlayer.js +67 -0
  14. package/dist/cjs/LensPlayer.js.map +1 -0
  15. package/dist/cjs/index.d.ts +17 -0
  16. package/dist/cjs/index.d.ts.map +1 -0
  17. package/dist/cjs/index.js +34 -0
  18. package/dist/cjs/index.js.map +1 -0
  19. package/dist/cjs/internal/bootstrapUtils.d.ts +13 -0
  20. package/dist/cjs/internal/bootstrapUtils.d.ts.map +1 -0
  21. package/dist/cjs/internal/bootstrapUtils.js +29 -0
  22. package/dist/cjs/internal/bootstrapUtils.js.map +1 -0
  23. package/dist/cjs/internal/error.d.ts +2 -0
  24. package/dist/cjs/internal/error.d.ts.map +1 -0
  25. package/dist/cjs/internal/error.js +30 -0
  26. package/dist/cjs/internal/error.js.map +1 -0
  27. package/dist/cjs/internal/isMobile.d.ts +5 -0
  28. package/dist/cjs/internal/isMobile.d.ts.map +1 -0
  29. package/dist/cjs/internal/isMobile.js +15 -0
  30. package/dist/cjs/internal/isMobile.js.map +1 -0
  31. package/dist/cjs/internal/logging.d.ts +40 -0
  32. package/dist/cjs/internal/logging.d.ts.map +1 -0
  33. package/dist/cjs/internal/logging.js +63 -0
  34. package/dist/cjs/internal/logging.js.map +1 -0
  35. package/dist/cjs/internal/metrics.d.ts +29 -0
  36. package/dist/cjs/internal/metrics.d.ts.map +1 -0
  37. package/dist/cjs/internal/metrics.js +128 -0
  38. package/dist/cjs/internal/metrics.js.map +1 -0
  39. package/dist/cjs/internal/sessionUtils.d.ts +3 -0
  40. package/dist/cjs/internal/sessionUtils.d.ts.map +1 -0
  41. package/dist/cjs/internal/sessionUtils.js +17 -0
  42. package/dist/cjs/internal/sessionUtils.js.map +1 -0
  43. package/dist/cjs/internal/sourceUtils.d.ts +22 -0
  44. package/dist/cjs/internal/sourceUtils.d.ts.map +1 -0
  45. package/dist/cjs/internal/sourceUtils.js +143 -0
  46. package/dist/cjs/internal/sourceUtils.js.map +1 -0
  47. package/dist/cjs/package.json +1 -0
  48. package/dist/cjs/types.d.ts +96 -0
  49. package/dist/cjs/types.d.ts.map +1 -0
  50. package/dist/cjs/types.js +26 -0
  51. package/dist/cjs/types.js.map +1 -0
  52. package/dist/cjs/useApplyLens.d.ts +25 -0
  53. package/dist/cjs/useApplyLens.d.ts.map +1 -0
  54. package/dist/cjs/useApplyLens.js +87 -0
  55. package/dist/cjs/useApplyLens.js.map +1 -0
  56. package/dist/cjs/useApplySource.d.ts +11 -0
  57. package/dist/cjs/useApplySource.d.ts.map +1 -0
  58. package/dist/cjs/useApplySource.js +66 -0
  59. package/dist/cjs/useApplySource.js.map +1 -0
  60. package/dist/cjs/usePlaybackOptions.d.ts +38 -0
  61. package/dist/cjs/usePlaybackOptions.d.ts.map +1 -0
  62. package/dist/cjs/usePlaybackOptions.js +51 -0
  63. package/dist/cjs/usePlaybackOptions.js.map +1 -0
  64. package/dist/cjs/version.d.ts +3 -0
  65. package/dist/cjs/version.d.ts.map +1 -0
  66. package/dist/cjs/version.js +6 -0
  67. package/dist/cjs/version.js.map +1 -0
  68. package/dist/esm/CameraKitProvider.d.ts +203 -0
  69. package/dist/esm/CameraKitProvider.d.ts.map +1 -0
  70. package/dist/esm/CameraKitProvider.js +533 -0
  71. package/dist/esm/CameraKitProvider.js.map +1 -0
  72. package/dist/esm/Canvas.d.ts +7 -0
  73. package/dist/esm/Canvas.d.ts.map +1 -0
  74. package/dist/esm/Canvas.js +45 -0
  75. package/dist/esm/Canvas.js.map +1 -0
  76. package/dist/esm/LensPlayer.d.ts +101 -0
  77. package/dist/esm/LensPlayer.d.ts.map +1 -0
  78. package/dist/esm/LensPlayer.js +63 -0
  79. package/dist/esm/LensPlayer.js.map +1 -0
  80. package/dist/esm/index.d.ts +17 -0
  81. package/dist/esm/index.d.ts.map +1 -0
  82. package/dist/esm/index.js +13 -0
  83. package/dist/esm/index.js.map +1 -0
  84. package/dist/esm/internal/bootstrapUtils.d.ts +13 -0
  85. package/dist/esm/internal/bootstrapUtils.d.ts.map +1 -0
  86. package/dist/esm/internal/bootstrapUtils.js +26 -0
  87. package/dist/esm/internal/bootstrapUtils.js.map +1 -0
  88. package/dist/esm/internal/error.d.ts +2 -0
  89. package/dist/esm/internal/error.d.ts.map +1 -0
  90. package/dist/esm/internal/error.js +27 -0
  91. package/dist/esm/internal/error.js.map +1 -0
  92. package/dist/esm/internal/isMobile.d.ts +5 -0
  93. package/dist/esm/internal/isMobile.d.ts.map +1 -0
  94. package/dist/esm/internal/isMobile.js +12 -0
  95. package/dist/esm/internal/isMobile.js.map +1 -0
  96. package/dist/esm/internal/logging.d.ts +40 -0
  97. package/dist/esm/internal/logging.d.ts.map +1 -0
  98. package/dist/esm/internal/logging.js +58 -0
  99. package/dist/esm/internal/logging.js.map +1 -0
  100. package/dist/esm/internal/metrics.d.ts +29 -0
  101. package/dist/esm/internal/metrics.d.ts.map +1 -0
  102. package/dist/esm/internal/metrics.js +91 -0
  103. package/dist/esm/internal/metrics.js.map +1 -0
  104. package/dist/esm/internal/sessionUtils.d.ts +3 -0
  105. package/dist/esm/internal/sessionUtils.d.ts.map +1 -0
  106. package/dist/esm/internal/sessionUtils.js +14 -0
  107. package/dist/esm/internal/sessionUtils.js.map +1 -0
  108. package/dist/esm/internal/sourceUtils.d.ts +22 -0
  109. package/dist/esm/internal/sourceUtils.d.ts.map +1 -0
  110. package/dist/esm/internal/sourceUtils.js +139 -0
  111. package/dist/esm/internal/sourceUtils.js.map +1 -0
  112. package/dist/esm/types.d.ts +96 -0
  113. package/dist/esm/types.d.ts.map +1 -0
  114. package/dist/esm/types.js +20 -0
  115. package/dist/esm/types.js.map +1 -0
  116. package/dist/esm/useApplyLens.d.ts +25 -0
  117. package/dist/esm/useApplyLens.d.ts.map +1 -0
  118. package/dist/esm/useApplyLens.js +81 -0
  119. package/dist/esm/useApplyLens.js.map +1 -0
  120. package/dist/esm/useApplySource.d.ts +11 -0
  121. package/dist/esm/useApplySource.d.ts.map +1 -0
  122. package/dist/esm/useApplySource.js +60 -0
  123. package/dist/esm/useApplySource.js.map +1 -0
  124. package/dist/esm/usePlaybackOptions.d.ts +38 -0
  125. package/dist/esm/usePlaybackOptions.d.ts.map +1 -0
  126. package/dist/esm/usePlaybackOptions.js +48 -0
  127. package/dist/esm/usePlaybackOptions.js.map +1 -0
  128. package/dist/esm/version.d.ts +3 -0
  129. package/dist/esm/version.d.ts.map +1 -0
  130. package/dist/esm/version.js +3 -0
  131. package/dist/esm/version.js.map +1 -0
  132. package/package.json +94 -0
@@ -0,0 +1,91 @@
1
+ import { Count, ConcatInjectable, Injectable } from "@snap/camera-kit";
2
+ import * as CameraKitModule from "@snap/camera-kit";
3
+ import { Subject } from "rxjs";
4
+ import { VERSION } from "../version";
5
+ /**
6
+ * Namespace alias for runtime feature detection.
7
+ * This allows graceful degradation across Camera Kit versions:
8
+ * - Newer: `externalMetricsFactory`
9
+ * - Older: `externalMetricsSubjectFactory`
10
+ * - Unknown future: neither → metrics injection is silently skipped.
11
+ *
12
+ * TODO: once Camera Kit peer dependency is >= 1.15.0,
13
+ * we can remove the legacy code path and import externalMetricsFactory directly.
14
+ */
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ const ck = CameraKitModule;
17
+ const METRICS_PREFIX = "react_camera_kit";
18
+ /** Single module-level Subject shared across all bootstrap cycles. */
19
+ const metricsSubject = new Subject();
20
+ /**
21
+ * Tracks the forwarding subscription used by the legacy API path.
22
+ * Only relevant when Camera Kit does not export `externalMetricsFactory`.
23
+ */
24
+ let forwardingSubscription;
25
+ /**
26
+ * Creates a metrics reporter that pushes Count metrics into a Subject.
27
+ * The subject is wired into Camera Kit's DI container so metrics flow
28
+ * through the SDK's built-in pipeline to the backend.
29
+ */
30
+ function createMetricsReporter(subject) {
31
+ return {
32
+ reportCount(name) {
33
+ subject.next(Count.count(`${METRICS_PREFIX}_${name}`, 1, {
34
+ rck_version: sanitizeMetricFragment(VERSION),
35
+ }));
36
+ },
37
+ };
38
+ }
39
+ /** Global metrics reporter — safe to call at any point; events are buffered until the DI wiring is established. */
40
+ export const metricsReporter = createMetricsReporter(metricsSubject);
41
+ /**
42
+ * Wraps a user-supplied `extendContainer` (if any) so that our metrics Subject
43
+ * is always provided into Camera Kit's DI container.
44
+ *
45
+ * Newer Camera Kit versions (with `externalMetricsFactory`)
46
+ * use a simpler declarative approach. Older versions fall back to
47
+ * `externalMetricsSubjectFactory` with manual subscribe-and-forward.
48
+ *
49
+ * On re-bootstrap the previous forwarding subscription is torn down automatically
50
+ * (legacy path only; the new path doesn't need that).
51
+ */
52
+ export function extendContainerWithMetrics(userExtendContainer) {
53
+ return (container) => {
54
+ const result = userExtendContainer ? userExtendContainer(container) : container;
55
+ // Resolve lazily — the export may or may not exist depending on the CK version.
56
+ const metricsFactory = ck["externalMetricsFactory"];
57
+ const subjectFactory = ck["externalMetricsSubjectFactory"];
58
+ // Newer Camera Kit: externalMetricsFactory
59
+ if (metricsFactory) {
60
+ return result.provides(getNewInjectable(metricsFactory, metricsSubject));
61
+ }
62
+ // Fallback: older Camera Kit externalMetricsSubjectFactory
63
+ if (subjectFactory) {
64
+ return result.provides(getLegacyInjectable(subjectFactory, metricsSubject));
65
+ }
66
+ // Neither API surface available — skip metrics injection.
67
+ return result;
68
+ };
69
+ }
70
+ function getNewInjectable(factory, metricsSubject) {
71
+ return ConcatInjectable(factory.token, () => metricsSubject.asObservable());
72
+ }
73
+ function getLegacyInjectable(factory, metricsSubject) {
74
+ return Injectable(factory.token, [factory.token], (existingSubject) => {
75
+ // Tear down previous forwarding subscription before creating a new one.
76
+ forwardingSubscription?.unsubscribe();
77
+ // Only forward `next` events – we must never propagate `error` or `complete`
78
+ // to the shared Subject, as that would terminate the metrics pipeline for
79
+ // all consumers.
80
+ forwardingSubscription = metricsSubject.subscribe({
81
+ next: (metric) => existingSubject.next(metric),
82
+ error: () => { },
83
+ complete: () => { },
84
+ });
85
+ return existingSubject;
86
+ });
87
+ }
88
+ function sanitizeMetricFragment(fragment) {
89
+ return fragment.toLowerCase().replaceAll(".", "_");
90
+ }
91
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/internal/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA2B,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,KAAK,eAAe,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAc,OAAO,EAAgB,MAAM,MAAM,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAcrC;;;;;;;;;GASG;AACH,8DAA8D;AAC9D,MAAM,EAAE,GAAG,eAAsC,CAAC;AAElD,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,sEAAsE;AACtE,MAAM,cAAc,GAAG,IAAI,OAAO,EAAU,CAAC;AAE7C;;;GAGG;AACH,IAAI,sBAAgD,CAAC;AAIrD;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,OAAwB;IACrD,OAAO;QACL,WAAW,CAAC,IAAY;YACtB,OAAO,CAAC,IAAI,CACV,KAAK,CAAC,KAAK,CAAC,GAAG,cAAc,IAAI,IAAI,EAAE,EAAE,CAAC,EAAE;gBAC1C,WAAW,EAAE,sBAAsB,CAAC,OAAO,CAAC;aAC7C,CAAC,CACH,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,mHAAmH;AACnH,MAAM,CAAC,MAAM,eAAe,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;AAErE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,0BAA0B,CACxC,mBAAqE;IAErE,OAAO,CAAC,SAA0B,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEhF,gFAAgF;QAChF,MAAM,cAAc,GAAG,EAAE,CAAC,wBAAwB,CAAuC,CAAC;QAC1F,MAAM,cAAc,GAAG,EAAE,CAAC,+BAA+B,CAA8C,CAAC;QAExG,2CAA2C;QAC3C,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC;QAC3E,CAAC;QAED,2DAA2D;QAC3D,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC;QAC9E,CAAC;QAED,0DAA0D;QAC1D,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA+B,EAAE,cAA+B;IACxF,OAAO,gBAAgB,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAsC,EAAE,cAA+B;IAClG,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,KAAK,CAAU,EAAE,CAAC,eAAgC,EAAE,EAAE;QAC9F,wEAAwE;QACxE,sBAAsB,EAAE,WAAW,EAAE,CAAC;QAEtC,6EAA6E;QAC7E,0EAA0E;QAC1E,iBAAiB;QACjB,sBAAsB,GAAG,cAAc,CAAC,SAAS,CAAC;YAChD,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;YAC9C,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;YACf,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;SACnB,CAAC,CAAC;QACH,OAAO,eAAe,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import { Count, Metric, PublicContainer, ConcatInjectable, Injectable } from \"@snap/camera-kit\";\nimport * as CameraKitModule from \"@snap/camera-kit\";\nimport { Observable, Subject, Subscription } from \"rxjs\";\nimport { VERSION } from \"../version\";\n\ntype ExternalMetricsFactory = {\n (): Observable<Metric>[];\n token: \"externalMetrics\";\n dependencies: [];\n};\n\ntype ExternalMetricsSubjectFactory = {\n (): Subject<Metric>;\n token: \"externalMetricsSubject\";\n dependencies: [];\n};\n\n/**\n * Namespace alias for runtime feature detection.\n * This allows graceful degradation across Camera Kit versions:\n * - Newer: `externalMetricsFactory`\n * - Older: `externalMetricsSubjectFactory`\n * - Unknown future: neither → metrics injection is silently skipped.\n *\n * TODO: once Camera Kit peer dependency is >= 1.15.0,\n * we can remove the legacy code path and import externalMetricsFactory directly.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst ck = CameraKitModule as Record<string, any>;\n\nconst METRICS_PREFIX = \"react_camera_kit\";\n\n/** Single module-level Subject shared across all bootstrap cycles. */\nconst metricsSubject = new Subject<Metric>();\n\n/**\n * Tracks the forwarding subscription used by the legacy API path.\n * Only relevant when Camera Kit does not export `externalMetricsFactory`.\n */\nlet forwardingSubscription: Subscription | undefined;\n\nexport type MetricsReporter = ReturnType<typeof createMetricsReporter>;\n\n/**\n * Creates a metrics reporter that pushes Count metrics into a Subject.\n * The subject is wired into Camera Kit's DI container so metrics flow\n * through the SDK's built-in pipeline to the backend.\n */\nfunction createMetricsReporter(subject: Subject<Metric>) {\n return {\n reportCount(name: string) {\n subject.next(\n Count.count(`${METRICS_PREFIX}_${name}`, 1, {\n rck_version: sanitizeMetricFragment(VERSION),\n }),\n );\n },\n };\n}\n\n/** Global metrics reporter — safe to call at any point; events are buffered until the DI wiring is established. */\nexport const metricsReporter = createMetricsReporter(metricsSubject);\n\n/**\n * Wraps a user-supplied `extendContainer` (if any) so that our metrics Subject\n * is always provided into Camera Kit's DI container.\n *\n * Newer Camera Kit versions (with `externalMetricsFactory`)\n * use a simpler declarative approach. Older versions fall back to\n * `externalMetricsSubjectFactory` with manual subscribe-and-forward.\n *\n * On re-bootstrap the previous forwarding subscription is torn down automatically\n * (legacy path only; the new path doesn't need that).\n */\nexport function extendContainerWithMetrics(\n userExtendContainer?: (container: PublicContainer) => PublicContainer,\n): (container: PublicContainer) => PublicContainer {\n return (container: PublicContainer) => {\n const result = userExtendContainer ? userExtendContainer(container) : container;\n\n // Resolve lazily — the export may or may not exist depending on the CK version.\n const metricsFactory = ck[\"externalMetricsFactory\"] as ExternalMetricsFactory | undefined;\n const subjectFactory = ck[\"externalMetricsSubjectFactory\"] as ExternalMetricsSubjectFactory | undefined;\n\n // Newer Camera Kit: externalMetricsFactory\n if (metricsFactory) {\n return result.provides(getNewInjectable(metricsFactory, metricsSubject));\n }\n\n // Fallback: older Camera Kit externalMetricsSubjectFactory\n if (subjectFactory) {\n return result.provides(getLegacyInjectable(subjectFactory, metricsSubject));\n }\n\n // Neither API surface available — skip metrics injection.\n return result;\n };\n}\n\nfunction getNewInjectable(factory: ExternalMetricsFactory, metricsSubject: Subject<Metric>) {\n return ConcatInjectable(factory.token, () => metricsSubject.asObservable());\n}\n\nfunction getLegacyInjectable(factory: ExternalMetricsSubjectFactory, metricsSubject: Subject<Metric>) {\n return Injectable(factory.token, [factory.token] as const, (existingSubject: Subject<Metric>) => {\n // Tear down previous forwarding subscription before creating a new one.\n forwardingSubscription?.unsubscribe();\n\n // Only forward `next` events – we must never propagate `error` or `complete`\n // to the shared Subject, as that would terminate the metrics pipeline for\n // all consumers.\n forwardingSubscription = metricsSubject.subscribe({\n next: (metric) => existingSubject.next(metric),\n error: () => {},\n complete: () => {},\n });\n return existingSubject;\n });\n}\n\nfunction sanitizeMetricFragment(fragment: string) {\n return fragment.toLowerCase().replaceAll(\".\", \"_\");\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { CameraKitSession } from "@snap/camera-kit";
2
+ export declare function withSessionPaused<T>(session: CameraKitSession, cb: () => Promise<T>): Promise<T>;
3
+ //# sourceMappingURL=sessionUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionUtils.d.ts","sourceRoot":"","sources":["../../../src/internal/sessionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,cAazF"}
@@ -0,0 +1,14 @@
1
+ export async function withSessionPaused(session, cb) {
2
+ const { capture, live } = session.playing;
3
+ // Pause everything in parallel
4
+ await Promise.all([capture && session.pause("capture"), live && session.pause("live")]);
5
+ try {
6
+ // Run the user callback while paused
7
+ return await cb();
8
+ }
9
+ finally {
10
+ // Always resume, even if cb() throws
11
+ await Promise.all([capture && session.play("capture"), live && session.play("live")]);
12
+ }
13
+ }
14
+ //# sourceMappingURL=sessionUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionUtils.js","sourceRoot":"","sources":["../../../src/internal/sessionUtils.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAI,OAAyB,EAAE,EAAoB;IACxF,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAE1C,+BAA+B;IAC/B,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAExF,IAAI,CAAC;QACH,qCAAqC;QACrC,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,qCAAqC;QACrC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACxF,CAAC;AACH,CAAC","sourcesContent":["import { CameraKitSession } from \"@snap/camera-kit\";\n\nexport async function withSessionPaused<T>(session: CameraKitSession, cb: () => Promise<T>) {\n const { capture, live } = session.playing;\n\n // Pause everything in parallel\n await Promise.all([capture && session.pause(\"capture\"), live && session.pause(\"live\")]);\n\n try {\n // Run the user callback while paused\n return await cb();\n } finally {\n // Always resume, even if cb() throws\n await Promise.all([capture && session.play(\"capture\"), live && session.play(\"live\")]);\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { SourceInput, SourceOutput } from "../types";
2
+ import { CameraKitSource, Transform2D } from "@snap/camera-kit";
3
+ export declare const DEFAULT_CAMERA_DEVICE_ID = "";
4
+ type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N ? R : _TupleOf<T, N, [T, ...R]>;
5
+ export type TupleOf<T, N extends number> = N extends N ? (number extends N ? T[] : _TupleOf<T, N, []>) : never;
6
+ export declare const defaultStreamResolution: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ export interface SourceApplication {
11
+ cameraKitSource: CameraKitSource;
12
+ transform: Transform2D;
13
+ /**
14
+ * Dimensions of the input source in pixels, as [width, height], or undefined if unavailable.
15
+ */
16
+ inputSize?: [number, number];
17
+ mediaStream?: MediaStream;
18
+ initializedSourceInput: SourceOutput;
19
+ }
20
+ export declare function createCameraKitSource(source: SourceInput): Promise<SourceApplication>;
21
+ export {};
22
+ //# sourceMappingURL=sourceUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceUtils.d.ts","sourceRoot":"","sources":["../../../src/internal/sourceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmD,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACtG,OAAO,EACL,eAAe,EAIf,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAG1B,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAChH,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;AAE/G,eAAO,MAAM,uBAAuB;;;CAGnC,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,WAAW,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,sBAAsB,EAAE,YAAY,CAAC;CACtC;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqB3F"}
@@ -0,0 +1,139 @@
1
+ import { createImageSource, createMediaStreamSource, createVideoSource, Transform2D, } from "@snap/camera-kit";
2
+ import { isMobile } from "./isMobile";
3
+ export const DEFAULT_CAMERA_DEVICE_ID = "";
4
+ export const defaultStreamResolution = {
5
+ width: 1280,
6
+ height: 720,
7
+ };
8
+ export async function createCameraKitSource(source) {
9
+ if (source.kind === "camera") {
10
+ return createCameraStreamSource({
11
+ // undefined deviceId brings default camera
12
+ deviceId: source.deviceId !== DEFAULT_CAMERA_DEVICE_ID ? source.deviceId : undefined,
13
+ cameraFacing: source.options?.cameraFacing ?? "user",
14
+ cameraConstraints: source.options?.cameraConstraints ?? defaultStreamResolution,
15
+ cameraRotation: source.options?.cameraRotation ?? 0,
16
+ fpsLimit: source.options?.fpsLimit,
17
+ });
18
+ }
19
+ else if (source.kind === "video") {
20
+ return createCameraKitVideoSource({
21
+ videoUrl: source.url,
22
+ autoplay: source.autoplay,
23
+ });
24
+ }
25
+ else if (source.kind === "image") {
26
+ return createCameraKitImageSource({
27
+ imageUrl: source.url,
28
+ });
29
+ }
30
+ throw new Error(`Unsupported source kind`);
31
+ }
32
+ async function createCameraStreamSource({ deviceId, cameraConstraints, cameraFacing, fpsLimit, cameraRotation, }) {
33
+ const mediaStream = await navigator.mediaDevices.getUserMedia({
34
+ video: {
35
+ ...cameraConstraints,
36
+ deviceId: isMobile() ? undefined : deviceId,
37
+ facingMode: cameraFacing,
38
+ },
39
+ audio: false,
40
+ });
41
+ const track = mediaStream.getVideoTracks()[0];
42
+ const { width, height, deviceId: actualDeviceId } = track?.getSettings() ?? {};
43
+ const cameraKitSource = createMediaStreamSource(mediaStream, {
44
+ cameraType: cameraFacing,
45
+ fpsLimit,
46
+ });
47
+ // On some mobile browsers, track settings can initially report landscape
48
+ // dimensions even when the device is held in portrait, so we normalize by
49
+ // treating mobile capture as rotated when deriving input size.
50
+ const rotate = isMobile() || Math.abs(cameraRotation) === 90;
51
+ const mirror = cameraFacing === "user";
52
+ const transform = new Transform2D(getTransform(cameraRotation, mirror));
53
+ return {
54
+ cameraKitSource,
55
+ transform,
56
+ inputSize: typeof width === "number" && typeof height === "number"
57
+ ? [rotate ? height : width, rotate ? width : height]
58
+ : undefined,
59
+ mediaStream,
60
+ initializedSourceInput: {
61
+ kind: "camera",
62
+ deviceId: actualDeviceId ?? "",
63
+ label: track?.label ?? "",
64
+ },
65
+ };
66
+ }
67
+ function createCameraKitVideoSource({ videoUrl, autoplay }) {
68
+ return new Promise((res, rej) => {
69
+ autoplay = autoplay ?? true;
70
+ const videoInput = document.createElement("video");
71
+ videoInput.src = videoUrl;
72
+ videoInput.autoplay = autoplay;
73
+ videoInput.muted = true;
74
+ videoInput.loop = true;
75
+ videoInput.crossOrigin = "anonymous";
76
+ videoInput.playsInline = true;
77
+ videoInput.addEventListener("canplay", async () => {
78
+ if (autoplay)
79
+ await videoInput.play();
80
+ res({
81
+ cameraKitSource: createVideoSource(videoInput),
82
+ transform: Transform2D.Identity,
83
+ inputSize: [videoInput.videoWidth, videoInput.videoHeight],
84
+ initializedSourceInput: {
85
+ kind: "video",
86
+ url: videoUrl,
87
+ videoElement: videoInput,
88
+ },
89
+ });
90
+ }, { once: true });
91
+ videoInput.addEventListener("error", async (event) => {
92
+ rej(new Error(event.message ?? "Unable to load video.", {
93
+ cause: event.error,
94
+ }));
95
+ }, { once: true });
96
+ });
97
+ }
98
+ function createCameraKitImageSource({ imageUrl }) {
99
+ return new Promise((res, rej) => {
100
+ const imageInput = document.createElement("img");
101
+ imageInput.src = imageUrl;
102
+ imageInput.crossOrigin = "anonymous";
103
+ imageInput.addEventListener("load", async () => {
104
+ res({
105
+ cameraKitSource: createImageSource(imageInput),
106
+ transform: Transform2D.Identity,
107
+ inputSize: [imageInput.naturalWidth, imageInput.naturalHeight],
108
+ initializedSourceInput: {
109
+ kind: "image",
110
+ url: imageUrl,
111
+ imageElement: imageInput,
112
+ },
113
+ });
114
+ }, { once: true });
115
+ imageInput.addEventListener("error", async (event) => {
116
+ rej(new Error(event.message ?? "Unable to load image.", {
117
+ cause: event.error,
118
+ }));
119
+ }, { once: true });
120
+ });
121
+ }
122
+ function getTransform(degrees, mirror) {
123
+ const mirrorFactor = mirror ? -1 : 1;
124
+ const rad = (degrees * Math.PI) / 180;
125
+ const cos = Number(Math.cos(rad).toFixed(2));
126
+ const sin = Number(Math.sin(rad).toFixed(2));
127
+ let normalizedDegrees = degrees % 360;
128
+ if (normalizedDegrees < 0)
129
+ normalizedDegrees += 360;
130
+ const quadrant = Math.floor(normalizedDegrees / 90) % 4;
131
+ let translateX = quadrant === 1 || quadrant === 2 ? 1 : 0;
132
+ let translateY = quadrant === 2 || quadrant === 3 ? 1 : 0;
133
+ if (mirror) {
134
+ translateX = quadrant === 0 || quadrant === 2 ? 1 - translateX : translateX;
135
+ translateY = quadrant === 1 || quadrant === 3 ? 1 - translateY : translateY;
136
+ }
137
+ return [cos * mirrorFactor, sin * mirrorFactor, 0, sin === 0 ? 0 : -sin, cos, 0, translateX, translateY, 1];
138
+ }
139
+ //# sourceMappingURL=sourceUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceUtils.js","sourceRoot":"","sources":["../../../src/internal/sourceUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { CameraConstraints, CameraFacing, CameraRotation, SourceInput, SourceOutput } from \"../types\";\nimport {\n CameraKitSource,\n createImageSource,\n createMediaStreamSource,\n createVideoSource,\n Transform2D,\n} from \"@snap/camera-kit\";\nimport { isMobile } from \"./isMobile\";\n\nexport const DEFAULT_CAMERA_DEVICE_ID = \"\";\n\ntype _TupleOf<T, N extends number, R extends unknown[]> = R[\"length\"] extends N ? R : _TupleOf<T, N, [T, ...R]>;\nexport type TupleOf<T, N extends number> = N extends N ? (number extends N ? T[] : _TupleOf<T, N, []>) : never;\n\nexport const defaultStreamResolution = {\n width: 1280,\n height: 720,\n};\n\nexport interface SourceApplication {\n cameraKitSource: CameraKitSource;\n transform: Transform2D;\n /**\n * Dimensions of the input source in pixels, as [width, height], or undefined if unavailable.\n */\n inputSize?: [number, number];\n mediaStream?: MediaStream;\n initializedSourceInput: SourceOutput;\n}\n\nexport async function createCameraKitSource(source: SourceInput): Promise<SourceApplication> {\n if (source.kind === \"camera\") {\n return createCameraStreamSource({\n // undefined deviceId brings default camera\n deviceId: source.deviceId !== DEFAULT_CAMERA_DEVICE_ID ? source.deviceId : undefined,\n cameraFacing: source.options?.cameraFacing ?? \"user\",\n cameraConstraints: source.options?.cameraConstraints ?? defaultStreamResolution,\n cameraRotation: source.options?.cameraRotation ?? 0,\n fpsLimit: source.options?.fpsLimit,\n });\n } else if (source.kind === \"video\") {\n return createCameraKitVideoSource({\n videoUrl: source.url,\n autoplay: source.autoplay,\n });\n } else if (source.kind === \"image\") {\n return createCameraKitImageSource({\n imageUrl: source.url,\n });\n }\n throw new Error(`Unsupported source kind`);\n}\n\nasync function createCameraStreamSource({\n deviceId,\n cameraConstraints,\n cameraFacing,\n fpsLimit,\n cameraRotation,\n}: {\n deviceId: string | undefined;\n cameraConstraints: CameraConstraints;\n cameraFacing: CameraFacing;\n fpsLimit: number | undefined;\n cameraRotation: CameraRotation;\n}): Promise<SourceApplication> {\n const mediaStream = await navigator.mediaDevices.getUserMedia({\n video: {\n ...cameraConstraints,\n deviceId: isMobile() ? undefined : deviceId,\n facingMode: cameraFacing,\n },\n audio: false,\n });\n\n const track = mediaStream.getVideoTracks()[0];\n const { width, height, deviceId: actualDeviceId } = track?.getSettings() ?? {};\n\n const cameraKitSource = createMediaStreamSource(mediaStream, {\n cameraType: cameraFacing,\n fpsLimit,\n });\n\n // On some mobile browsers, track settings can initially report landscape\n // dimensions even when the device is held in portrait, so we normalize by\n // treating mobile capture as rotated when deriving input size.\n const rotate = isMobile() || Math.abs(cameraRotation) === 90;\n const mirror = cameraFacing === \"user\";\n const transform = new Transform2D(getTransform(cameraRotation, mirror));\n\n return {\n cameraKitSource,\n transform,\n inputSize:\n typeof width === \"number\" && typeof height === \"number\"\n ? [rotate ? height : width, rotate ? width : height]\n : undefined,\n mediaStream,\n initializedSourceInput: {\n kind: \"camera\",\n deviceId: actualDeviceId ?? \"\",\n label: track?.label ?? \"\",\n },\n };\n}\n\nfunction createCameraKitVideoSource({ videoUrl, autoplay }: { videoUrl: string; autoplay?: boolean }) {\n return new Promise<SourceApplication>((res, rej) => {\n autoplay = autoplay ?? true;\n const videoInput = document.createElement(\"video\");\n videoInput.src = videoUrl;\n videoInput.autoplay = autoplay;\n videoInput.muted = true;\n videoInput.loop = true;\n videoInput.crossOrigin = \"anonymous\";\n videoInput.playsInline = true;\n videoInput.addEventListener(\n \"canplay\",\n async () => {\n if (autoplay) await videoInput.play();\n res({\n cameraKitSource: createVideoSource(videoInput),\n transform: Transform2D.Identity,\n inputSize: [videoInput.videoWidth, videoInput.videoHeight],\n initializedSourceInput: {\n kind: \"video\",\n url: videoUrl,\n videoElement: videoInput,\n },\n });\n },\n { once: true },\n );\n videoInput.addEventListener(\n \"error\",\n async (event) => {\n rej(\n new Error(event.message ?? \"Unable to load video.\", {\n cause: event.error,\n }),\n );\n },\n { once: true },\n );\n });\n}\n\nfunction createCameraKitImageSource({ imageUrl }: { imageUrl: string }) {\n return new Promise<SourceApplication>((res, rej) => {\n const imageInput = document.createElement(\"img\");\n imageInput.src = imageUrl;\n imageInput.crossOrigin = \"anonymous\";\n imageInput.addEventListener(\n \"load\",\n async () => {\n res({\n cameraKitSource: createImageSource(imageInput),\n transform: Transform2D.Identity,\n inputSize: [imageInput.naturalWidth, imageInput.naturalHeight],\n initializedSourceInput: {\n kind: \"image\",\n url: imageUrl,\n imageElement: imageInput,\n },\n });\n },\n { once: true },\n );\n imageInput.addEventListener(\n \"error\",\n async (event) => {\n rej(\n new Error(event.message ?? \"Unable to load image.\", {\n cause: event.error,\n }),\n );\n },\n { once: true },\n );\n });\n}\n\nfunction getTransform(degrees: number, mirror: boolean): TupleOf<number, 9> {\n const mirrorFactor = mirror ? -1 : 1;\n const rad = (degrees * Math.PI) / 180;\n const cos = Number(Math.cos(rad).toFixed(2));\n const sin = Number(Math.sin(rad).toFixed(2));\n\n let normalizedDegrees = degrees % 360;\n if (normalizedDegrees < 0) normalizedDegrees += 360;\n\n const quadrant = Math.floor(normalizedDegrees / 90) % 4;\n\n let translateX = quadrant === 1 || quadrant === 2 ? 1 : 0;\n let translateY = quadrant === 2 || quadrant === 3 ? 1 : 0;\n\n if (mirror) {\n translateX = quadrant === 0 || quadrant === 2 ? 1 - translateX : translateX;\n translateY = quadrant === 1 || quadrant === 3 ? 1 - translateY : translateY;\n }\n\n return [cos * mirrorFactor, sin * mirrorFactor, 0, sin === 0 ? 0 : -sin, cos, 0, translateX, translateY, 1];\n}\n"]}
@@ -0,0 +1,96 @@
1
+ import { Lens, LensLaunchData } from "@snap/camera-kit";
2
+ export type SourceStatus = {
3
+ state: "none";
4
+ } | {
5
+ state: "loading";
6
+ } | {
7
+ state: "ready";
8
+ } | {
9
+ state: "error";
10
+ error: Error;
11
+ };
12
+ export type LensStatus = {
13
+ state: "none";
14
+ } | {
15
+ state: "loading";
16
+ } | {
17
+ state: "ready";
18
+ } | {
19
+ state: "error";
20
+ error: Error;
21
+ };
22
+ export interface CurrentSource {
23
+ status: "none" | "loading" | "ready" | "error";
24
+ error: Error | undefined;
25
+ input: SourceInput | undefined;
26
+ initializedInput: SourceOutput | undefined;
27
+ }
28
+ export interface CurrentLens {
29
+ status: "none" | "loading" | "ready" | "error";
30
+ error: Error | undefined;
31
+ lensId: string | undefined;
32
+ lensGroupId: string | undefined;
33
+ lensLaunchData: LensLaunchData | undefined;
34
+ lensReadyGuard: (() => Promise<void>) | undefined;
35
+ lens: Lens | undefined;
36
+ }
37
+ export declare const NO_CURRENT_LENS: CurrentLens;
38
+ export type CameraSourceInput = {
39
+ kind: "camera";
40
+ deviceId?: string;
41
+ options?: SourceOptions;
42
+ };
43
+ export type VideoSourceInput = {
44
+ kind: "video";
45
+ url: string;
46
+ autoplay?: boolean;
47
+ };
48
+ export type ImageSourceInput = {
49
+ kind: "image";
50
+ url: string;
51
+ };
52
+ export type SourceInput = CameraSourceInput | VideoSourceInput | ImageSourceInput;
53
+ export declare function isCameraSource(source: SourceInput | undefined): source is CameraSourceInput;
54
+ export declare function isVideoSource(source: SourceInput | undefined): source is VideoSourceInput;
55
+ export declare function isImageSource(source: SourceInput | undefined): source is ImageSourceInput;
56
+ export interface CameraInfo {
57
+ kind: "camera";
58
+ deviceId: string;
59
+ label: string;
60
+ }
61
+ export type CameraSourceOutput = CameraInfo;
62
+ export type VideoSourceOutput = {
63
+ kind: "video";
64
+ url: string;
65
+ videoElement: HTMLVideoElement;
66
+ };
67
+ export type ImageSourceOutput = {
68
+ kind: "image";
69
+ url: string;
70
+ imageElement: HTMLImageElement;
71
+ };
72
+ export type SourceOutput = CameraSourceOutput | VideoSourceOutput | ImageSourceOutput;
73
+ /** Explicit, fixed‐pixel dimensions */
74
+ export interface FixedOutputSize {
75
+ mode: "fixed";
76
+ width: number;
77
+ height: number;
78
+ }
79
+ /** Exactly match whatever the camera/input delivers */
80
+ export interface MatchInputSize {
81
+ mode: "match-input";
82
+ }
83
+ export declare const CameraRotationOptions: readonly [0, -90, 90, 180];
84
+ export type OutputSize = MatchInputSize | FixedOutputSize;
85
+ export interface SourceOptions {
86
+ cameraFacing?: CameraFacing;
87
+ cameraConstraints?: CameraConstraints;
88
+ cameraRotation?: CameraRotation;
89
+ fpsLimit?: number;
90
+ outputSize?: OutputSize;
91
+ }
92
+ export type CameraFacing = "user" | "environment";
93
+ export type CameraConstraints = MediaTrackConstraints;
94
+ export type CameraRotation = (typeof CameraRotationOptions)[number];
95
+ export type CanvasType = "live" | "capture";
96
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export const NO_CURRENT_LENS = {
2
+ status: "none",
3
+ error: undefined,
4
+ lensId: undefined,
5
+ lensGroupId: undefined,
6
+ lensLaunchData: undefined,
7
+ lensReadyGuard: undefined,
8
+ lens: undefined,
9
+ };
10
+ export function isCameraSource(source) {
11
+ return source?.kind === "camera";
12
+ }
13
+ export function isVideoSource(source) {
14
+ return source?.kind === "video";
15
+ }
16
+ export function isImageSource(source) {
17
+ return source?.kind === "image";
18
+ }
19
+ export const CameraRotationOptions = [0, -90, 90, 180];
20
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,WAAW,EAAE,SAAS;IACtB,cAAc,EAAE,SAAS;IACzB,cAAc,EAAE,SAAS;IACzB,IAAI,EAAE,SAAS;CAChB,CAAC;AAgBF,MAAM,UAAU,cAAc,CAAC,MAA+B;IAC5D,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAA+B;IAC3D,OAAO,MAAM,EAAE,IAAI,KAAK,OAAO,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAA+B;IAC3D,OAAO,MAAM,EAAE,IAAI,KAAK,OAAO,CAAC;AAClC,CAAC;AAkCD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAU,CAAC","sourcesContent":["import { Lens, LensLaunchData } from \"@snap/camera-kit\";\n\nexport type SourceStatus =\n | { state: \"none\" }\n | { state: \"loading\" }\n | { state: \"ready\" }\n | { state: \"error\"; error: Error };\n\nexport type LensStatus =\n | { state: \"none\" }\n | { state: \"loading\" }\n | { state: \"ready\" }\n | { state: \"error\"; error: Error };\n\nexport interface CurrentSource {\n status: \"none\" | \"loading\" | \"ready\" | \"error\";\n error: Error | undefined;\n input: SourceInput | undefined;\n initializedInput: SourceOutput | undefined;\n}\n\nexport interface CurrentLens {\n status: \"none\" | \"loading\" | \"ready\" | \"error\";\n error: Error | undefined;\n lensId: string | undefined;\n lensGroupId: string | undefined;\n lensLaunchData: LensLaunchData | undefined;\n lensReadyGuard: (() => Promise<void>) | undefined;\n lens: Lens | undefined;\n}\n\nexport const NO_CURRENT_LENS: CurrentLens = {\n status: \"none\",\n error: undefined,\n lensId: undefined,\n lensGroupId: undefined,\n lensLaunchData: undefined,\n lensReadyGuard: undefined,\n lens: undefined,\n};\n\nexport type CameraSourceInput = {\n kind: \"camera\";\n deviceId?: string;\n options?: SourceOptions;\n};\nexport type VideoSourceInput = {\n kind: \"video\";\n url: string;\n autoplay?: boolean;\n};\nexport type ImageSourceInput = { kind: \"image\"; url: string };\n\nexport type SourceInput = CameraSourceInput | VideoSourceInput | ImageSourceInput;\n\nexport function isCameraSource(source: SourceInput | undefined): source is CameraSourceInput {\n return source?.kind === \"camera\";\n}\n\nexport function isVideoSource(source: SourceInput | undefined): source is VideoSourceInput {\n return source?.kind === \"video\";\n}\n\nexport function isImageSource(source: SourceInput | undefined): source is ImageSourceInput {\n return source?.kind === \"image\";\n}\n\nexport interface CameraInfo {\n kind: \"camera\";\n deviceId: string;\n label: string;\n}\n\nexport type CameraSourceOutput = CameraInfo;\nexport type VideoSourceOutput = {\n kind: \"video\";\n url: string;\n videoElement: HTMLVideoElement;\n};\nexport type ImageSourceOutput = {\n kind: \"image\";\n url: string;\n imageElement: HTMLImageElement;\n};\n\nexport type SourceOutput = CameraSourceOutput | VideoSourceOutput | ImageSourceOutput;\n\n/** Explicit, fixed‐pixel dimensions */\nexport interface FixedOutputSize {\n mode: \"fixed\";\n width: number;\n height: number;\n}\n\n/** Exactly match whatever the camera/input delivers */\nexport interface MatchInputSize {\n mode: \"match-input\";\n}\n\nexport const CameraRotationOptions = [0, -90, 90, 180] as const;\n\nexport type OutputSize = MatchInputSize | FixedOutputSize;\n\nexport interface SourceOptions {\n cameraFacing?: CameraFacing;\n cameraConstraints?: CameraConstraints;\n cameraRotation?: CameraRotation;\n fpsLimit?: number;\n outputSize?: OutputSize;\n}\n\nexport type CameraFacing = \"user\" | \"environment\";\nexport type CameraConstraints = MediaTrackConstraints;\nexport type CameraRotation = (typeof CameraRotationOptions)[number];\n\nexport type CanvasType = \"live\" | \"capture\";\n"]}
@@ -0,0 +1,25 @@
1
+ import { LensLaunchData } from "@snap/camera-kit";
2
+ /**
3
+ * Declaratively applies a Lens to the current CameraKit session.
4
+ *
5
+ * This hook synchronizes the active lens with the provided parameters. When the lens ID,
6
+ * group ID, or launch data changes, the hook automatically applies the new lens or removes
7
+ * the current lens if parameters are cleared.
8
+ *
9
+ * @param lensId - The unique identifier of the lens to apply. If undefined, removes the current lens.
10
+ * @param lensGroupId - The group ID containing the lens. Required when lensId is provided.
11
+ * @param lensLaunchData - Optional launch parameters to pass to the lens.
12
+ * @param lensReadyGuard - Optional async guard that must resolve before the lens is considered ready.
13
+ * Useful for coordinating lens application with animations or other async operations.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * // Simple lens application
18
+ * useApplyLens("lens-id-123", "my-group");
19
+ *
20
+ * // With launch data
21
+ * useApplyLens("lens-id-123", "my-group", { launchParams: { hint: "face" } });
22
+ * ```
23
+ */
24
+ export declare function useApplyLens(lensId?: string, lensGroupId?: string, lensLaunchData?: LensLaunchData, lensReadyGuard?: () => Promise<void>): void;
25
+ //# sourceMappingURL=useApplyLens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useApplyLens.d.ts","sourceRoot":"","sources":["../../src/useApplyLens.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,cAAc,EAC/B,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QA4DrC"}
@@ -0,0 +1,81 @@
1
+ import { useEffect, useMemo, useRef } from "react";
2
+ import hash from "stable-hash";
3
+ import { useInternalCameraKit } from "./CameraKitProvider";
4
+ /**
5
+ * Declaratively applies a Lens to the current CameraKit session.
6
+ *
7
+ * This hook synchronizes the active lens with the provided parameters. When the lens ID,
8
+ * group ID, or launch data changes, the hook automatically applies the new lens or removes
9
+ * the current lens if parameters are cleared.
10
+ *
11
+ * @param lensId - The unique identifier of the lens to apply. If undefined, removes the current lens.
12
+ * @param lensGroupId - The group ID containing the lens. Required when lensId is provided.
13
+ * @param lensLaunchData - Optional launch parameters to pass to the lens.
14
+ * @param lensReadyGuard - Optional async guard that must resolve before the lens is considered ready.
15
+ * Useful for coordinating lens application with animations or other async operations.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // Simple lens application
20
+ * useApplyLens("lens-id-123", "my-group");
21
+ *
22
+ * // With launch data
23
+ * useApplyLens("lens-id-123", "my-group", { launchParams: { hint: "face" } });
24
+ * ```
25
+ */
26
+ export function useApplyLens(lensId, lensGroupId, lensLaunchData, lensReadyGuard) {
27
+ const { cameraKit, sdkStatus, currentSession, applyLens, removeLens, getLogger } = useInternalCameraKit();
28
+ const log = getLogger("useApplyLens");
29
+ const launchKey = hash(lensLaunchData);
30
+ const safeLaunchData = useMemo(() => lensLaunchData, [launchKey]);
31
+ // Don’t put lensReadyGuard in the dependency array of the “apply-lens” effect:
32
+ // the caller often passes it as an inline function, so its identity
33
+ // changes on every render. Re-running the whole lens-apply sequence just
34
+ // because the guard’s reference changed doesn't make any sense.
35
+ // It does make sense ony next time lens is applied.
36
+ // Instead, we store the latest guard in a ref that we update after each re-render.
37
+ const guardRef = useRef(lensReadyGuard);
38
+ useEffect(() => {
39
+ guardRef.current = lensReadyGuard;
40
+ });
41
+ // Synchronize the current CameraKit session with the requested Lens.
42
+ // * Runs when lensId, lensGroupId, or lensLaunchData meaningfully change (see stable-key check).
43
+ // * Applies the Lens once, with an abort-guard so late resolutions don’t touch an unmounted component.
44
+ useEffect(() => {
45
+ if (sdkStatus !== "ready" || !cameraKit || !currentSession)
46
+ return;
47
+ if (!lensId || !lensGroupId) {
48
+ removeLens();
49
+ return;
50
+ }
51
+ let cancelled = false;
52
+ const started = performance.now();
53
+ log.info("apply_attempt", { lensId, groupId: lensGroupId });
54
+ (async () => {
55
+ try {
56
+ await applyLens(lensId, lensGroupId, safeLaunchData, guardRef.current);
57
+ if (cancelled) {
58
+ await removeLens();
59
+ return;
60
+ }
61
+ log.info("apply_success", {
62
+ lensId,
63
+ groupId: lensGroupId,
64
+ elapsedMs: Math.round(performance.now() - started),
65
+ });
66
+ }
67
+ catch (err) {
68
+ if (cancelled)
69
+ return;
70
+ log.error("apply_failure", { lensId, groupId: lensGroupId }, err);
71
+ }
72
+ })();
73
+ return () => {
74
+ cancelled = true;
75
+ removeLens().catch((err) => {
76
+ log.warn("remove_on_unmount_failed", { lensId, groupId: lensGroupId }, err);
77
+ });
78
+ };
79
+ }, [lensId, lensGroupId, launchKey, sdkStatus, cameraKit, currentSession, applyLens, removeLens, log]);
80
+ }
81
+ //# sourceMappingURL=useApplyLens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useApplyLens.js","sourceRoot":"","sources":["../../src/useApplyLens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,IAAI,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAe,EACf,WAAoB,EACpB,cAA+B,EAC/B,cAAoC;IAEpC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,oBAAoB,EAAE,CAAC;IAC1G,MAAM,GAAG,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;IAEtC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAElE,+EAA+E;IAC/E,oEAAoE;IACpE,yEAAyE;IACzE,gEAAgE;IAChE,oDAAoD;IACpD,mFAAmF;IACnF,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACxC,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,OAAO,GAAG,cAAc,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,sEAAsE;IACtE,mGAAmG;IACnG,yGAAyG;IACzG,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,KAAK,OAAO,IAAI,CAAC,SAAS,IAAI,CAAC,cAAc;YAAE,OAAO;QAEnE,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5B,UAAU,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAElC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAE5D,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACvE,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,UAAU,EAAE,CAAC;oBACnB,OAAO;gBACT,CAAC;gBACD,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE;oBACxB,MAAM;oBACN,OAAO,EAAE,WAAW;oBACpB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;iBACnD,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,SAAS;oBAAE,OAAO;gBACtB,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACzB,GAAG,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9E,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AACzG,CAAC","sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport { LensLaunchData } from \"@snap/camera-kit\";\nimport hash from \"stable-hash\";\nimport { useInternalCameraKit } from \"./CameraKitProvider\";\n\n/**\n * Declaratively applies a Lens to the current CameraKit session.\n *\n * This hook synchronizes the active lens with the provided parameters. When the lens ID,\n * group ID, or launch data changes, the hook automatically applies the new lens or removes\n * the current lens if parameters are cleared.\n *\n * @param lensId - The unique identifier of the lens to apply. If undefined, removes the current lens.\n * @param lensGroupId - The group ID containing the lens. Required when lensId is provided.\n * @param lensLaunchData - Optional launch parameters to pass to the lens.\n * @param lensReadyGuard - Optional async guard that must resolve before the lens is considered ready.\n * Useful for coordinating lens application with animations or other async operations.\n *\n * @example\n * ```tsx\n * // Simple lens application\n * useApplyLens(\"lens-id-123\", \"my-group\");\n *\n * // With launch data\n * useApplyLens(\"lens-id-123\", \"my-group\", { launchParams: { hint: \"face\" } });\n * ```\n */\nexport function useApplyLens(\n lensId?: string,\n lensGroupId?: string,\n lensLaunchData?: LensLaunchData,\n lensReadyGuard?: () => Promise<void>,\n) {\n const { cameraKit, sdkStatus, currentSession, applyLens, removeLens, getLogger } = useInternalCameraKit();\n const log = getLogger(\"useApplyLens\");\n\n const launchKey = hash(lensLaunchData);\n const safeLaunchData = useMemo(() => lensLaunchData, [launchKey]);\n\n // Don’t put lensReadyGuard in the dependency array of the “apply-lens” effect:\n // the caller often passes it as an inline function, so its identity\n // changes on every render. Re-running the whole lens-apply sequence just\n // because the guard’s reference changed doesn't make any sense.\n // It does make sense ony next time lens is applied.\n // Instead, we store the latest guard in a ref that we update after each re-render.\n const guardRef = useRef(lensReadyGuard);\n useEffect(() => {\n guardRef.current = lensReadyGuard;\n });\n\n // Synchronize the current CameraKit session with the requested Lens.\n // * Runs when lensId, lensGroupId, or lensLaunchData meaningfully change (see stable-key check).\n // * Applies the Lens once, with an abort-guard so late resolutions don’t touch an unmounted component.\n useEffect(() => {\n if (sdkStatus !== \"ready\" || !cameraKit || !currentSession) return;\n\n if (!lensId || !lensGroupId) {\n removeLens();\n return;\n }\n\n let cancelled = false;\n const started = performance.now();\n\n log.info(\"apply_attempt\", { lensId, groupId: lensGroupId });\n\n (async () => {\n try {\n await applyLens(lensId, lensGroupId, safeLaunchData, guardRef.current);\n if (cancelled) {\n await removeLens();\n return;\n }\n log.info(\"apply_success\", {\n lensId,\n groupId: lensGroupId,\n elapsedMs: Math.round(performance.now() - started),\n });\n } catch (err) {\n if (cancelled) return;\n log.error(\"apply_failure\", { lensId, groupId: lensGroupId }, err);\n }\n })();\n\n return () => {\n cancelled = true;\n removeLens().catch((err) => {\n log.warn(\"remove_on_unmount_failed\", { lensId, groupId: lensGroupId }, err);\n });\n };\n }, [lensId, lensGroupId, launchKey, sdkStatus, cameraKit, currentSession, applyLens, removeLens, log]);\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { OutputSize, SourceInput } from "./types";
2
+ /**
3
+ * Declarative hook to apply a source to the current CameraKit session.
4
+ * This is a thin wrapper around the imperative `applySource` and `removeSource` methods
5
+ * exposed by `useCameraKit()`.
6
+ *
7
+ * @param source - The source input (camera, video, or image)
8
+ * @param outputSize - Optional output size configuration
9
+ */
10
+ export declare function useApplySource(source?: SourceInput, outputSize?: OutputSize): void;
11
+ //# sourceMappingURL=useApplySource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useApplySource.d.ts","sourceRoot":"","sources":["../../src/useApplySource.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,WAAgC,EAAE,UAAU,CAAC,EAAE,UAAU,QAmD/F"}