@momentco-ai/moment-sdk 0.1.2 → 0.2.0-dev.13

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/README.md CHANGED
@@ -29,7 +29,7 @@ npm install @momentco-ai/moment-sdk
29
29
  <button
30
30
  class="moment-sync-trigger"
31
31
  data-moment-team-slug="your-team-slug"
32
- data-external-event-id="event-001"
32
+ data-moment-slug="event-001"
33
33
  data-moment-trigger-type="moment"
34
34
  >
35
35
  Add to Calendar
@@ -71,9 +71,9 @@ Place these on any element matching the trigger selector (default: `.moment-sync
71
71
  | Attribute | Required | Description |
72
72
  | -------------------------- | -------- | ------------------------------------------------------------ |
73
73
  | `data-moment-team-slug` | ✅ | Team/brand slug |
74
- | `data-external-event-id` | No | Specific event identifier (resolved to real ID by Moment) |
75
- | `data-moment-list-slug` | No | List slug (resolved to moment IDs by Moment) |
76
- | `data-moment-trigger-type` | No | `moment` (default), `list`, or `schedule` |
74
+ | `data-moment-slug` | No | Brand-level moment slug (resolved to real ID by Moment) |
75
+ | `data-moment-list-slug` | No | List slug (resolved to a list-level subscription by Moment) |
76
+ | `data-moment-trigger-type` | No | `moment` (default), `list`, or `team` |
77
77
  | `data-moment-ids` | No | Comma-separated moment IDs (fallback if slugs don't resolve) |
78
78
  | `data-moment-game-id` | No | Alias for `data-moment-ids` |
79
79
  | `data-moment-calendar` | No | Pre-select provider: `google` or `outlook` |
@@ -93,7 +93,7 @@ You can also open the modal programmatically instead of relying on data attribut
93
93
  // Open modal
94
94
  sdk.open({
95
95
  teamSlug: 'your-team-slug',
96
- externalEventId: 'event-123',
96
+ momentSlug: 'event-123',
97
97
  triggerType: 'moment',
98
98
  ids: ['moment-id-1'],
99
99
  calendar: 'google', // optional: skip provider selection
@@ -120,7 +120,7 @@ Programmatically create a styled trigger button:
120
120
  <script>
121
121
  const btn = createMomentButton({
122
122
  teamSlug: 'your-team-slug',
123
- externalEventId: 'event-001',
123
+ momentSlug: 'event-001',
124
124
  triggerType: 'moment',
125
125
  label: 'Add to Calendar',
126
126
  });
@@ -161,7 +161,7 @@ You can customize trigger button appearance in a few ways:
161
161
  <script>
162
162
  const primaryBtn = createMomentButton({
163
163
  teamSlug: 'your-team-slug',
164
- externalEventId: 'event-001',
164
+ momentSlug: 'event-001',
165
165
  triggerType: 'moment',
166
166
  label: 'Get Tickets + Calendar',
167
167
  className: 'my-calendar-btn',
@@ -177,7 +177,7 @@ You can also create plain HTML triggers and fully own styles/text:
177
177
  <button
178
178
  class="my-calendar-btn moment-sync-trigger"
179
179
  data-moment-team-slug="your-team-slug"
180
- data-external-event-id="event-001"
180
+ data-moment-slug="event-001"
181
181
  data-moment-trigger-type="moment"
182
182
  >
183
183
  Add This Match to My Calendar
@@ -221,7 +221,7 @@ All callbacks (`onSuccess`, `onError`, `onClose`) receive a result payload:
221
221
  "type": "moment.embed.result",
222
222
  "result": "success | error | cancelled",
223
223
  "provider": "google | outlook",
224
- "triggerType": "moment | list | schedule",
224
+ "triggerType": "moment | list | team",
225
225
  "momentIds": ["..."],
226
226
  "message": "optional details"
227
227
  }
@@ -1 +1 @@
1
- (function(u){"use strict";class g{popup=null;pollTimer=null;messageHandler=null;resultReceived=!1;opts;constructor(e){this.opts=e}open(e){this.cleanup(),this.resultReceived=!1;const t=this.buildPopupUrl(e),s=Math.round(window.screenX+(window.outerWidth-500)/2),r=Math.round(window.screenY+(window.outerHeight-700)/2);if(this.popup=window.open(t,"moment-oauth-popup",`width=500,height=700,left=${s},top=${r},menubar=no,toolbar=no,location=yes,status=no`),!this.popup||this.popup.closed){this.sendStatusToIframe("popup-blocked"),this.opts.onPopupBlocked();return}this.sendStatusToIframe("popup-opened"),this.startPolling(),this.messageHandler=i=>{if(i.origin!==this.opts.liveOrigin||i.source!==this.popup)return;const o=i.data;!o||typeof o!="object"||o.source!=="moment-live-embed"||o.type!=="moment.embed.result"||(this.resultReceived=!0,this.sendStatusToIframe("completed"),this.opts.iframeWindow&&this.opts.iframeWindow.postMessage(o,this.opts.liveOrigin),this.opts.onResult(o),this.cleanup())},window.addEventListener("message",this.messageHandler)}cleanup(){if(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.popup&&!this.popup.closed)try{this.popup.close()}catch{}this.popup=null}buildPopupUrl(e){const t=window.location.origin,s=new URLSearchParams({provider:e.provider,teamSlug:e.teamSlug,ids:e.ids.join(","),triggerType:e.triggerType,returnOrigin:t});return`${this.opts.liveBaseUrl}/en/embed/oauth-popup?${s.toString()}`}startPolling(){this.pollTimer=setInterval(()=>{(!this.popup||this.popup.closed)&&(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.resultReceived||(this.sendStatusToIframe("popup-closed"),this.opts.onPopupClosed()),this.cleanup())},500)}sendStatusToIframe(e){if(!this.opts.iframeWindow)return;const t={source:"moment-sdk",type:"moment.embed.oauth.status",status:e};this.opts.iframeWindow.postMessage(t,this.opts.liveOrigin)}}const f=".moment-sync-trigger",v="https://live.momentco.ai";class m{opts;liveBaseUrl;liveOrigin;overlay=null;iframe=null;popupBridge=null;messageHandler=null;boundClickHandlers=new Map;activePayload=null;previousFocusedElement=null;previousBodyOverflow="";didManageBodyOverflow=!1;closeTimer=null;constructor(e){this.opts={triggerSelector:f,...e},this.liveBaseUrl=v;try{this.liveOrigin=new URL(this.liveBaseUrl).origin}catch{throw new Error(`[MomentSdk] Invalid VITE_LIVE_BASE_URL: "${this.liveBaseUrl}"`)}this.bindTriggers(),this.emitAnalytics("embed.init")}open(e){this.emitAnalytics("embed.open",{teamSlug:e.teamSlug,triggerType:e.triggerType}),this.createModal(e)}close(){this.handleCancel()}rebind(){this.unbindTriggers(),this.bindTriggers()}destroy(){this.cleanup(),this.unbindTriggers()}bindTriggers(){document.querySelectorAll(this.opts.triggerSelector).forEach(t=>{const s=i=>{i.preventDefault(),this.handleTriggerClick(t)},r=this.boundClickHandlers.get(t);r&&t.removeEventListener("click",r),t.addEventListener("click",s),this.boundClickHandlers.set(t,s)})}unbindTriggers(){this.boundClickHandlers.forEach((e,t)=>{t.removeEventListener("click",e)}),this.boundClickHandlers.clear()}handleTriggerClick(e){const t=e.getAttribute("data-moment-team-slug")??"",s=e.getAttribute("data-external-event-id")??void 0,r=e.getAttribute("data-moment-list-slug")??void 0,i=e.getAttribute("data-moment-trigger-type");let o="moment";i!=null&&i!==""&&(i==="moment"||i==="list"||i==="schedule"?o=i:console.warn("[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",i));const l=e.getAttribute("data-moment-ids")??e.getAttribute("data-moment-game-id")??"",d=l?l.split(",").filter(Boolean):[],a=e.getAttribute("data-moment-calendar");let c;if(a!=null&&a!==""&&(a==="google"||a==="outlook"?c=a:console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:",a)),!t){console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");return}this.emitAnalytics("embed.trigger.click",{teamSlug:t,triggerType:o,momentIds:d}),this.open({teamSlug:t,externalEventId:s,listSlug:r,triggerType:o,ids:d,calendar:c??void 0})}createModal(e){this.cleanup(),this.previousFocusedElement=document.activeElement||null,this.activePayload=e;const t=this.buildIframeUrl(e);this.overlay=document.createElement("div"),this.overlay.setAttribute("role","presentation"),Object.assign(this.overlay.style,{position:"fixed",inset:"0",zIndex:"999999",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",padding:"16px"}),this.overlay.addEventListener("click",l=>{l.target===this.overlay&&this.handleCancel()});const s=l=>{l.key==="Escape"&&this.handleCancel()};document.addEventListener("keydown",s);const r=document.createElement("div");r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),r.setAttribute("aria-label","Calendar sync modal"),r.tabIndex=-1,Object.assign(r.style,{position:"relative",width:"100%",maxWidth:"420px",maxHeight:"90vh",borderRadius:"16px",overflow:"hidden",backgroundColor:"#ffffff",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)"});const i=document.createElement("button");i.type="button",i.textContent="ⓧ",i.setAttribute("aria-label","Close"),Object.assign(i.style,{position:"absolute",top:"8px",right:"8px",zIndex:"10",border:"none",backgroundColor:"transparent",color:"#999",fontSize:"20px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}),i.addEventListener("click",()=>this.handleCancel()),this.iframe=document.createElement("iframe"),this.iframe.src=t,this.iframe.setAttribute("allow",""),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),Object.assign(this.iframe.style,{width:"100%",height:"480px",border:"none",display:"block"}),r.appendChild(i),r.appendChild(this.iframe),this.overlay.appendChild(r),document.body.appendChild(this.overlay);const o=l=>{if(l.key!=="Tab")return;const d=r.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(d.length===0){l.preventDefault(),r.focus();return}const a=d[0],c=d[d.length-1],h=document.activeElement;l.shiftKey&&h===a?(l.preventDefault(),c.focus()):!l.shiftKey&&h===c&&(l.preventDefault(),a.focus())};r.addEventListener("keydown",o),i.focus(),this.previousBodyOverflow=document.body.style.overflow,document.body.style.overflow="hidden",this.didManageBodyOverflow=!0,this.setupMessageListener(),this.overlay._escHandler=s,this.overlay._focusTrapHandler=o}buildIframeUrl(e){const t=new URLSearchParams;return t.set("teamSlug",e.teamSlug),e.externalEventId&&t.set("momentSlug",e.externalEventId),e.listSlug&&t.set("listSlug",e.listSlug),t.set("triggerType",e.triggerType),e.ids?.length&&t.set("ids",e.ids.join(",")),e.calendar&&t.set("calendar",e.calendar),t.set("returnOrigin",window.location.origin),t.set("embed","1"),`${this.liveBaseUrl}/en/embed/sync?${t.toString()}`}setupMessageListener(){this.messageHandler=e=>{if(e.origin!==this.liveOrigin||e.source!==this.iframe?.contentWindow)return;const t=e.data;if(!(!t||typeof t!="object")){if(t.source==="moment-live-embed"&&t.type==="moment.embed.oauth.start"){const s=t;this.emitAnalytics("oauth.start",{provider:s.provider,teamSlug:s.teamSlug}),this.handleOAuthStart(s);return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.result"){const s=t;this.handleResult(s)}}},window.addEventListener("message",this.messageHandler)}handleOAuthStart(e){this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.popupBridge=new g({liveBaseUrl:this.liveBaseUrl,liveOrigin:this.liveOrigin,iframeWindow:this.iframe?.contentWindow??null,onResult:t=>{this.handleResult(t)},onPopupBlocked:()=>{this.emitAnalytics("oauth.popup.blocked",{provider:e.provider})},onPopupClosed:()=>{this.emitAnalytics("oauth.popup.closed",{provider:e.provider})}}),this.popupBridge.open(e)}handleResult(e){if(e.result==="success")this.emitAnalytics("subscribe.success",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onSuccess?.(e);else if(e.result==="error")this.emitAnalytics("subscribe.error",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onError?.(e);else if(e.result==="cancelled")return;this.opts.onClose?.(e),this.emitAnalytics("embed.close"),this.closeTimer=setTimeout(()=>this.cleanup(),1500)}handleCancel(){this.emitAnalytics("embed.close");const t={source:"moment-live-embed",type:"moment.embed.result",result:"cancelled",triggerType:this.activePayload?.triggerType??"moment",momentIds:this.activePayload?.ids??[]};this.opts.onClose?.(t),this.cleanup()}cleanup(){if(this.closeTimer&&(clearTimeout(this.closeTimer),this.closeTimer=null),this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlay){const{_escHandler:e,_focusTrapHandler:t}=this.overlay;e&&document.removeEventListener("keydown",e);const s=this.overlay.firstElementChild;s&&t&&s.removeEventListener("keydown",t),this.overlay.remove(),this.overlay=null}this.iframe=null,this.activePayload=null,this.didManageBodyOverflow&&(document.body.style.overflow=this.previousBodyOverflow,this.didManageBodyOverflow=!1),this.previousFocusedElement&&typeof this.previousFocusedElement.focus=="function"&&this.previousFocusedElement.focus(),this.previousFocusedElement=null}emitAnalytics(e,t){this.opts.onAnalytics?.({event:e,timestamp:Date.now(),...t})}}function p(n){const e=document.createElement("button");return e.type="button",e.classList.add("moment-sync-trigger"),n.className&&n.className.split(" ").forEach(t=>{t&&e.classList.add(t)}),Object.assign(e.style,{backgroundColor:"#1c1917",color:"#ffffff",border:"1px solid #292524",borderRadius:"4px",padding:"8px 16px",fontSize:"14px",fontWeight:"500",cursor:"pointer",lineHeight:"1.4"}),e.setAttribute("data-moment-team-slug",n.teamSlug),n.externalEventId&&e.setAttribute("data-external-event-id",n.externalEventId),n.listSlug&&e.setAttribute("data-moment-list-slug",n.listSlug),n.triggerType&&e.setAttribute("data-moment-trigger-type",n.triggerType),n.ids?.length&&e.setAttribute("data-moment-ids",n.ids.join(",")),n.calendar&&e.setAttribute("data-moment-calendar",n.calendar),e.textContent=n.label??"Add to Calendar",e}if(typeof window<"u"){const n=window;n.MomentSdk=m,n.createMomentButton=p}u.MomentSdk=m,u.createMomentButton=p,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})})(this.MomentSdk=this.MomentSdk||{});
1
+ (function(h){"use strict";class y{popup=null;pollTimer=null;messageHandler=null;resultReceived=!1;opts;constructor(e){this.opts=e}open(e){this.cleanup(),this.resultReceived=!1;const t=this.buildPopupUrl(e),n=Math.round(window.screenX+(window.outerWidth-500)/2),r=Math.round(window.screenY+(window.outerHeight-700)/2);if(this.popup=window.open(t,"moment-oauth-popup",`width=500,height=700,left=${n},top=${r},menubar=no,toolbar=no,location=yes,status=no`),!this.popup||this.popup.closed){this.sendStatusToIframe("popup-blocked"),this.opts.onPopupBlocked();return}this.sendStatusToIframe("popup-opened"),this.startPolling(),this.messageHandler=i=>{if(i.origin!==this.opts.liveOrigin||i.source!==this.popup)return;const s=i.data;!s||typeof s!="object"||s.source!=="moment-live-embed"||s.type!=="moment.embed.result"||(this.resultReceived=!0,this.sendStatusToIframe("completed"),this.opts.iframeWindow&&this.opts.iframeWindow.postMessage(s,this.opts.liveOrigin),this.opts.onResult(s),this.cleanup())},window.addEventListener("message",this.messageHandler)}cleanup(){if(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.popup&&!this.popup.closed)try{this.popup.close()}catch{}this.popup=null}buildPopupUrl(e){const t=window.location.origin,n=new URLSearchParams({provider:e.provider,teamSlug:e.teamSlug,ids:e.ids.join(","),triggerType:e.triggerType,returnOrigin:t});return e.subscriptionType&&n.set("subscriptionType",e.subscriptionType),`${this.opts.liveBaseUrl}/en/embed/oauth-popup?${n.toString()}`}startPolling(){this.pollTimer=setInterval(()=>{(!this.popup||this.popup.closed)&&(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.resultReceived||(this.sendStatusToIframe("popup-closed"),this.opts.onPopupClosed()),this.cleanup())},500)}sendStatusToIframe(e){if(!this.opts.iframeWindow)return;const t={source:"moment-sdk",type:"moment.embed.oauth.status",status:e};this.opts.iframeWindow.postMessage(t,this.opts.liveOrigin)}}const w=".moment-sync-trigger",T="https://live.dev.momentco.ai";class g{opts;liveBaseUrl;liveOrigin;overlay=null;iframe=null;popupBridge=null;messageHandler=null;boundClickHandlers=new Map;activePayload=null;previousFocusedElement=null;previousBodyOverflow="";didManageBodyOverflow=!1;closeTimer=null;constructor(e){this.opts={triggerSelector:w,...e},this.liveBaseUrl=T;try{this.liveOrigin=new URL(this.liveBaseUrl).origin}catch{throw new Error(`[MomentSdk] Invalid VITE_LIVE_BASE_URL: "${this.liveBaseUrl}"`)}this.bindTriggers(),this.emitAnalytics("embed.init")}open(e){this.emitAnalytics("embed.open",{teamSlug:e.teamSlug,triggerType:e.triggerType}),this.createModal(e)}close(){this.handleCancel()}rebind(){this.unbindTriggers(),this.bindTriggers()}destroy(){this.cleanup(),this.unbindTriggers()}bindTriggers(){document.querySelectorAll(this.opts.triggerSelector).forEach(t=>{const n=i=>{i.preventDefault(),this.handleTriggerClick(t)},r=this.boundClickHandlers.get(t);r&&t.removeEventListener("click",r),t.addEventListener("click",n),this.boundClickHandlers.set(t,n)})}unbindTriggers(){this.boundClickHandlers.forEach((e,t)=>{t.removeEventListener("click",e)}),this.boundClickHandlers.clear()}handleTriggerClick(e){const t=e.getAttribute("data-moment-team-slug")??"",n=e.getAttribute("data-moment-slug")??void 0,r=e.getAttribute("data-moment-list-slug")??void 0,i=e.getAttribute("data-moment-trigger-type");let s="moment";i!=null&&i!==""&&(i==="moment"||i==="list"||i==="team"?s=i:console.warn("[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",i));const d=e.getAttribute("data-moment-ids")??e.getAttribute("data-moment-game-id")??"",u=d?d.split(",").filter(Boolean):[],a=e.getAttribute("data-moment-calendar");let m;if(a!=null&&a!==""&&(a==="google"||a==="outlook"?m=a:console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:",a)),!t){console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");return}const l=s==="team"?void 0:n,c=s==="team"?void 0:r,p=s==="team"?[]:u;this.emitAnalytics("embed.trigger.click",{teamSlug:t,triggerType:s,momentIds:p}),this.open({teamSlug:t,momentSlug:l,listSlug:c,triggerType:s,ids:p,calendar:m??void 0})}createModal(e){this.cleanup(),this.previousFocusedElement=document.activeElement||null,this.activePayload=e;const t=this.buildIframeUrl(e);this.overlay=document.createElement("div"),this.overlay.setAttribute("role","presentation"),Object.assign(this.overlay.style,{position:"fixed",inset:"0",zIndex:"999999",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",padding:"16px"}),this.overlay.addEventListener("click",l=>{l.target===this.overlay&&this.handleCancel()});const n=l=>{l.key==="Escape"&&this.handleCancel()};document.addEventListener("keydown",n);const r=document.createElement("div");Object.assign(r.style,{position:"relative",width:"100%",maxWidth:"380px",borderRadius:"16px",overflow:"hidden",backgroundColor:"#000000",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)",display:"flex",flexDirection:"column"});const i=document.createElement("div");i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true"),i.setAttribute("aria-label","Calendar sync modal"),i.tabIndex=-1,Object.assign(i.style,{position:"relative",width:"100%",maxHeight:"80vh",borderRadius:"12px",overflow:"auto",backgroundColor:"#ffffff"});const s=document.createElement("button");s.type="button",s.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>',s.setAttribute("aria-label","Close"),Object.assign(s.style,{position:"absolute",top:"10px",right:"10px",zIndex:"10",border:"none",backgroundColor:"transparent",color:"#999",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",padding:"0"}),s.addEventListener("mouseenter",()=>{s.style.color="#666"}),s.addEventListener("mouseleave",()=>{s.style.color="#999"}),s.addEventListener("click",()=>this.handleCancel()),this.iframe=document.createElement("iframe"),this.iframe.src=t,this.iframe.setAttribute("allow",""),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),this.iframe.setAttribute("scrolling","no"),Object.assign(this.iframe.style,{width:"100%",border:"none",display:"block",height:"420px",overflow:"hidden",transition:"height 0.15s ease"}),i.appendChild(s),i.appendChild(this.iframe);const d=document.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"12px 0"});const u=document.createElement("span");u.textContent="Powered by",Object.assign(u.style,{fontFamily:"Inter, system-ui, -apple-system, sans-serif",fontSize:"12px",lineHeight:"16px",color:"#ffffff"});const a=document.createElement("img");a.alt="Moment",a.src=`${this.liveBaseUrl}/brand/moment-text-white.png`,Object.assign(a.style,{height:"auto",width:"67px"}),d.appendChild(u),d.appendChild(a),r.appendChild(i),r.appendChild(d),this.overlay.appendChild(r),document.body.appendChild(this.overlay);const m=l=>{if(l.key!=="Tab")return;const c=i.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(c.length===0){l.preventDefault(),i.focus();return}const p=c[0],v=c[c.length-1],b=document.activeElement;l.shiftKey&&b===p?(l.preventDefault(),v.focus()):!l.shiftKey&&b===v&&(l.preventDefault(),p.focus())};i.addEventListener("keydown",m),s.focus(),this.previousBodyOverflow=document.body.style.overflow,document.body.style.overflow="hidden",this.didManageBodyOverflow=!0,this.setupMessageListener(),this.overlay._escHandler=n,this.overlay._focusTrapHandler=m}buildIframeUrl(e){const t=new URLSearchParams;return t.set("teamSlug",e.teamSlug),e.momentSlug&&t.set("momentSlug",e.momentSlug),e.listSlug&&t.set("listSlug",e.listSlug),t.set("triggerType",e.triggerType),e.ids?.length&&t.set("ids",e.ids.join(",")),e.calendar&&t.set("calendar",e.calendar),t.set("returnOrigin",window.location.origin),t.set("embed","1"),`${this.liveBaseUrl}/en/embed/sync?${t.toString()}`}setupMessageListener(){this.messageHandler=e=>{if(e.origin!==this.liveOrigin||e.source!==this.iframe?.contentWindow)return;const t=e.data;if(!(!t||typeof t!="object")){if(t.source==="moment-live-embed"&&t.type==="moment.embed.oauth.start"){const n=t;this.emitAnalytics("oauth.start",{provider:n.provider,teamSlug:n.teamSlug}),this.handleOAuthStart(n);return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.resize"){const n=typeof t.height=="number"?t.height:0;if(n>0&&this.iframe){const r=Math.round(window.innerHeight*.8);this.iframe.style.height=`${Math.min(n,r)}px`}return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.result"){const n=t;this.handleResult(n)}}},window.addEventListener("message",this.messageHandler)}handleOAuthStart(e){this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.popupBridge=new y({liveBaseUrl:this.liveBaseUrl,liveOrigin:this.liveOrigin,iframeWindow:this.iframe?.contentWindow??null,onResult:t=>{this.handleResult(t)},onPopupBlocked:()=>{this.emitAnalytics("oauth.popup.blocked",{provider:e.provider})},onPopupClosed:()=>{this.emitAnalytics("oauth.popup.closed",{provider:e.provider})}}),this.popupBridge.open(e)}handleResult(e){if(e.result==="success")this.emitAnalytics("subscribe.success",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onSuccess?.(e);else if(e.result==="error")this.emitAnalytics("subscribe.error",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onError?.(e);else if(e.result==="cancelled")return;this.opts.onClose?.(e),this.emitAnalytics("embed.close"),this.closeTimer=setTimeout(()=>this.cleanup(),1500)}handleCancel(){this.emitAnalytics("embed.close");const t={source:"moment-live-embed",type:"moment.embed.result",result:"cancelled",triggerType:this.activePayload?.triggerType??"moment",momentIds:this.activePayload?.ids??[]};this.opts.onClose?.(t),this.cleanup()}cleanup(){if(this.closeTimer&&(clearTimeout(this.closeTimer),this.closeTimer=null),this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlay){const{_escHandler:e,_focusTrapHandler:t}=this.overlay;e&&document.removeEventListener("keydown",e);const n=this.overlay.firstElementChild;n&&t&&n.removeEventListener("keydown",t),this.overlay.remove(),this.overlay=null}this.iframe=null,this.activePayload=null,this.didManageBodyOverflow&&(document.body.style.overflow=this.previousBodyOverflow,this.didManageBodyOverflow=!1),this.previousFocusedElement&&typeof this.previousFocusedElement.focus=="function"&&this.previousFocusedElement.focus(),this.previousFocusedElement=null}emitAnalytics(e,t){this.opts.onAnalytics?.({event:e,timestamp:Date.now(),...t})}}function f(o){const e=document.createElement("button");return e.type="button",e.classList.add("moment-sync-trigger"),o.className&&o.className.split(" ").forEach(t=>{t&&e.classList.add(t)}),Object.assign(e.style,{backgroundColor:"#1c1917",color:"#ffffff",border:"1px solid #292524",borderRadius:"4px",padding:"8px 16px",fontSize:"14px",fontWeight:"500",cursor:"pointer",lineHeight:"1.4"}),e.setAttribute("data-moment-team-slug",o.teamSlug),o.momentSlug&&e.setAttribute("data-moment-slug",o.momentSlug),o.listSlug&&e.setAttribute("data-moment-list-slug",o.listSlug),o.triggerType&&e.setAttribute("data-moment-trigger-type",o.triggerType),o.ids?.length&&e.setAttribute("data-moment-ids",o.ids.join(",")),o.calendar&&e.setAttribute("data-moment-calendar",o.calendar),e.textContent=o.label??"Add to Calendar",e}if(typeof window<"u"){const o=window;o.MomentSdk=g,o.createMomentButton=f}h.MomentSdk=g,h.createMomentButton=f,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})})(this.MomentSdk=this.MomentSdk||{});
@@ -1,4 +1,4 @@
1
- class m {
1
+ class f {
2
2
  popup = null;
3
3
  pollTimer = null;
4
4
  messageHandler = null;
@@ -12,19 +12,19 @@ class m {
12
12
  */
13
13
  open(e) {
14
14
  this.cleanup(), this.resultReceived = !1;
15
- const t = this.buildPopupUrl(e), s = Math.round(window.screenX + (window.outerWidth - 500) / 2), r = Math.round(window.screenY + (window.outerHeight - 700) / 2);
15
+ const t = this.buildPopupUrl(e), n = Math.round(window.screenX + (window.outerWidth - 500) / 2), r = Math.round(window.screenY + (window.outerHeight - 700) / 2);
16
16
  if (this.popup = window.open(
17
17
  t,
18
18
  "moment-oauth-popup",
19
- `width=500,height=700,left=${s},top=${r},menubar=no,toolbar=no,location=yes,status=no`
19
+ `width=500,height=700,left=${n},top=${r},menubar=no,toolbar=no,location=yes,status=no`
20
20
  ), !this.popup || this.popup.closed) {
21
21
  this.sendStatusToIframe("popup-blocked"), this.opts.onPopupBlocked();
22
22
  return;
23
23
  }
24
24
  this.sendStatusToIframe("popup-opened"), this.startPolling(), this.messageHandler = (i) => {
25
25
  if (i.origin !== this.opts.liveOrigin || i.source !== this.popup) return;
26
- const o = i.data;
27
- !o || typeof o != "object" || o.source !== "moment-live-embed" || o.type !== "moment.embed.result" || (this.resultReceived = !0, this.sendStatusToIframe("completed"), this.opts.iframeWindow && this.opts.iframeWindow.postMessage(o, this.opts.liveOrigin), this.opts.onResult(o), this.cleanup());
26
+ const s = i.data;
27
+ !s || typeof s != "object" || s.source !== "moment-live-embed" || s.type !== "moment.embed.result" || (this.resultReceived = !0, this.sendStatusToIframe("completed"), this.opts.iframeWindow && this.opts.iframeWindow.postMessage(s, this.opts.liveOrigin), this.opts.onResult(s), this.cleanup());
28
28
  }, window.addEventListener("message", this.messageHandler);
29
29
  }
30
30
  /**
@@ -39,14 +39,14 @@ class m {
39
39
  this.popup = null;
40
40
  }
41
41
  buildPopupUrl(e) {
42
- const t = window.location.origin, s = new URLSearchParams({
42
+ const t = window.location.origin, n = new URLSearchParams({
43
43
  provider: e.provider,
44
44
  teamSlug: e.teamSlug,
45
45
  ids: e.ids.join(","),
46
46
  triggerType: e.triggerType,
47
47
  returnOrigin: t
48
48
  });
49
- return `${this.opts.liveBaseUrl}/en/embed/oauth-popup?${s.toString()}`;
49
+ return e.subscriptionType && n.set("subscriptionType", e.subscriptionType), `${this.opts.liveBaseUrl}/en/embed/oauth-popup?${n.toString()}`;
50
50
  }
51
51
  startPolling() {
52
52
  this.pollTimer = setInterval(() => {
@@ -63,8 +63,8 @@ class m {
63
63
  this.opts.iframeWindow.postMessage(t, this.opts.liveOrigin);
64
64
  }
65
65
  }
66
- const p = ".moment-sync-trigger", h = "https://live.momentco.ai";
67
- class g {
66
+ const v = ".moment-sync-trigger", b = "https://live.dev.momentco.ai";
67
+ class y {
68
68
  opts;
69
69
  liveBaseUrl;
70
70
  liveOrigin;
@@ -80,9 +80,9 @@ class g {
80
80
  closeTimer = null;
81
81
  constructor(e) {
82
82
  this.opts = {
83
- triggerSelector: p,
83
+ triggerSelector: v,
84
84
  ...e
85
- }, this.liveBaseUrl = h;
85
+ }, this.liveBaseUrl = b;
86
86
  try {
87
87
  this.liveOrigin = new URL(this.liveBaseUrl).origin;
88
88
  } catch {
@@ -120,10 +120,10 @@ class g {
120
120
  // ── Private: trigger binding ──────────────────────────────────────
121
121
  bindTriggers() {
122
122
  document.querySelectorAll(this.opts.triggerSelector).forEach((t) => {
123
- const s = (i) => {
123
+ const n = (i) => {
124
124
  i.preventDefault(), this.handleTriggerClick(t);
125
125
  }, r = this.boundClickHandlers.get(t);
126
- r && t.removeEventListener("click", r), t.addEventListener("click", s), this.boundClickHandlers.set(t, s);
126
+ r && t.removeEventListener("click", r), t.addEventListener("click", n), this.boundClickHandlers.set(t, n);
127
127
  });
128
128
  }
129
129
  unbindTriggers() {
@@ -132,29 +132,30 @@ class g {
132
132
  }), this.boundClickHandlers.clear();
133
133
  }
134
134
  handleTriggerClick(e) {
135
- const t = e.getAttribute("data-moment-team-slug") ?? "", s = e.getAttribute("data-external-event-id") ?? void 0, r = e.getAttribute("data-moment-list-slug") ?? void 0, i = e.getAttribute("data-moment-trigger-type");
136
- let o = "moment";
137
- i != null && i !== "" && (i === "moment" || i === "list" || i === "schedule" ? o = i : console.warn(
135
+ const t = e.getAttribute("data-moment-team-slug") ?? "", n = e.getAttribute("data-moment-slug") ?? void 0, r = e.getAttribute("data-moment-list-slug") ?? void 0, i = e.getAttribute("data-moment-trigger-type");
136
+ let s = "moment";
137
+ i != null && i !== "" && (i === "moment" || i === "list" || i === "team" ? s = i : console.warn(
138
138
  "[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",
139
139
  i
140
140
  ));
141
- const l = e.getAttribute("data-moment-ids") ?? e.getAttribute("data-moment-game-id") ?? "", d = l ? l.split(",").filter(Boolean) : [], a = e.getAttribute("data-moment-calendar");
142
- let c;
143
- if (a != null && a !== "" && (a === "google" || a === "outlook" ? c = a : console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:", a)), !t) {
141
+ const d = e.getAttribute("data-moment-ids") ?? e.getAttribute("data-moment-game-id") ?? "", u = d ? d.split(",").filter(Boolean) : [], a = e.getAttribute("data-moment-calendar");
142
+ let m;
143
+ if (a != null && a !== "" && (a === "google" || a === "outlook" ? m = a : console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:", a)), !t) {
144
144
  console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");
145
145
  return;
146
146
  }
147
+ const l = s === "team" ? void 0 : n, c = s === "team" ? void 0 : r, p = s === "team" ? [] : u;
147
148
  this.emitAnalytics("embed.trigger.click", {
148
149
  teamSlug: t,
149
- triggerType: o,
150
- momentIds: d
150
+ triggerType: s,
151
+ momentIds: p
151
152
  }), this.open({
152
153
  teamSlug: t,
153
- externalEventId: s,
154
- listSlug: r,
155
- triggerType: o,
156
- ids: d,
157
- calendar: c ?? void 0
154
+ momentSlug: l,
155
+ listSlug: c,
156
+ triggerType: s,
157
+ ids: p,
158
+ calendar: m ?? void 0
158
159
  });
159
160
  }
160
161
  // ── Private: modal creation ───────────────────────────────────────
@@ -174,59 +175,96 @@ class g {
174
175
  }), this.overlay.addEventListener("click", (l) => {
175
176
  l.target === this.overlay && this.handleCancel();
176
177
  });
177
- const s = (l) => {
178
+ const n = (l) => {
178
179
  l.key === "Escape" && this.handleCancel();
179
180
  };
180
- document.addEventListener("keydown", s);
181
+ document.addEventListener("keydown", n);
181
182
  const r = document.createElement("div");
182
- r.setAttribute("role", "dialog"), r.setAttribute("aria-modal", "true"), r.setAttribute("aria-label", "Calendar sync modal"), r.tabIndex = -1, Object.assign(r.style, {
183
+ Object.assign(r.style, {
183
184
  position: "relative",
184
185
  width: "100%",
185
- maxWidth: "420px",
186
- maxHeight: "90vh",
186
+ maxWidth: "380px",
187
187
  borderRadius: "16px",
188
188
  overflow: "hidden",
189
- backgroundColor: "#ffffff",
190
- boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
189
+ backgroundColor: "#000000",
190
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
191
+ display: "flex",
192
+ flexDirection: "column"
193
+ });
194
+ const i = document.createElement("div");
195
+ i.setAttribute("role", "dialog"), i.setAttribute("aria-modal", "true"), i.setAttribute("aria-label", "Calendar sync modal"), i.tabIndex = -1, Object.assign(i.style, {
196
+ position: "relative",
197
+ width: "100%",
198
+ maxHeight: "80vh",
199
+ borderRadius: "12px",
200
+ overflow: "auto",
201
+ backgroundColor: "#ffffff"
191
202
  });
192
- const i = document.createElement("button");
193
- i.type = "button", i.textContent = "", i.setAttribute("aria-label", "Close"), Object.assign(i.style, {
203
+ const s = document.createElement("button");
204
+ s.type = "button", s.innerHTML = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>', s.setAttribute("aria-label", "Close"), Object.assign(s.style, {
194
205
  position: "absolute",
195
- top: "8px",
196
- right: "8px",
206
+ top: "10px",
207
+ right: "10px",
197
208
  zIndex: "10",
198
209
  border: "none",
199
210
  backgroundColor: "transparent",
200
211
  color: "#999",
201
- fontSize: "20px",
202
- lineHeight: "1",
203
212
  cursor: "pointer",
204
213
  display: "flex",
205
214
  alignItems: "center",
206
- justifyContent: "center"
207
- }), i.addEventListener("click", () => this.handleCancel()), this.iframe = document.createElement("iframe"), this.iframe.src = t, this.iframe.setAttribute("allow", ""), this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-popups allow-forms"), Object.assign(this.iframe.style, {
215
+ justifyContent: "center",
216
+ width: "24px",
217
+ height: "24px",
218
+ padding: "0"
219
+ }), s.addEventListener("mouseenter", () => {
220
+ s.style.color = "#666";
221
+ }), s.addEventListener("mouseleave", () => {
222
+ s.style.color = "#999";
223
+ }), s.addEventListener("click", () => this.handleCancel()), this.iframe = document.createElement("iframe"), this.iframe.src = t, this.iframe.setAttribute("allow", ""), this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-popups allow-forms"), this.iframe.setAttribute("scrolling", "no"), Object.assign(this.iframe.style, {
208
224
  width: "100%",
209
- height: "480px",
210
225
  border: "none",
211
- display: "block"
212
- }), r.appendChild(i), r.appendChild(this.iframe), this.overlay.appendChild(r), document.body.appendChild(this.overlay);
213
- const o = (l) => {
226
+ display: "block",
227
+ height: "420px",
228
+ overflow: "hidden",
229
+ transition: "height 0.15s ease"
230
+ }), i.appendChild(s), i.appendChild(this.iframe);
231
+ const d = document.createElement("div");
232
+ Object.assign(d.style, {
233
+ display: "flex",
234
+ alignItems: "center",
235
+ justifyContent: "center",
236
+ gap: "6px",
237
+ padding: "12px 0"
238
+ });
239
+ const u = document.createElement("span");
240
+ u.textContent = "Powered by", Object.assign(u.style, {
241
+ fontFamily: "Inter, system-ui, -apple-system, sans-serif",
242
+ fontSize: "12px",
243
+ lineHeight: "16px",
244
+ color: "#ffffff"
245
+ });
246
+ const a = document.createElement("img");
247
+ a.alt = "Moment", a.src = `${this.liveBaseUrl}/brand/moment-text-white.png`, Object.assign(a.style, {
248
+ height: "auto",
249
+ width: "67px"
250
+ }), d.appendChild(u), d.appendChild(a), r.appendChild(i), r.appendChild(d), this.overlay.appendChild(r), document.body.appendChild(this.overlay);
251
+ const m = (l) => {
214
252
  if (l.key !== "Tab") return;
215
- const d = r.querySelectorAll(
253
+ const c = i.querySelectorAll(
216
254
  'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
217
255
  );
218
- if (d.length === 0) {
219
- l.preventDefault(), r.focus();
256
+ if (c.length === 0) {
257
+ l.preventDefault(), i.focus();
220
258
  return;
221
259
  }
222
- const a = d[0], c = d[d.length - 1], u = document.activeElement;
223
- l.shiftKey && u === a ? (l.preventDefault(), c.focus()) : !l.shiftKey && u === c && (l.preventDefault(), a.focus());
260
+ const p = c[0], h = c[c.length - 1], g = document.activeElement;
261
+ l.shiftKey && g === p ? (l.preventDefault(), h.focus()) : !l.shiftKey && g === h && (l.preventDefault(), p.focus());
224
262
  };
225
- r.addEventListener("keydown", o), i.focus(), this.previousBodyOverflow = document.body.style.overflow, document.body.style.overflow = "hidden", this.didManageBodyOverflow = !0, this.setupMessageListener(), this.overlay._escHandler = s, this.overlay._focusTrapHandler = o;
263
+ i.addEventListener("keydown", m), s.focus(), this.previousBodyOverflow = document.body.style.overflow, document.body.style.overflow = "hidden", this.didManageBodyOverflow = !0, this.setupMessageListener(), this.overlay._escHandler = n, this.overlay._focusTrapHandler = m;
226
264
  }
227
265
  buildIframeUrl(e) {
228
266
  const t = new URLSearchParams();
229
- return t.set("teamSlug", e.teamSlug), e.externalEventId && t.set("momentSlug", e.externalEventId), e.listSlug && t.set("listSlug", e.listSlug), t.set("triggerType", e.triggerType), e.ids?.length && t.set("ids", e.ids.join(",")), e.calendar && t.set("calendar", e.calendar), t.set("returnOrigin", window.location.origin), t.set("embed", "1"), `${this.liveBaseUrl}/en/embed/sync?${t.toString()}`;
267
+ return t.set("teamSlug", e.teamSlug), e.momentSlug && t.set("momentSlug", e.momentSlug), e.listSlug && t.set("listSlug", e.listSlug), t.set("triggerType", e.triggerType), e.ids?.length && t.set("ids", e.ids.join(",")), e.calendar && t.set("calendar", e.calendar), t.set("returnOrigin", window.location.origin), t.set("embed", "1"), `${this.liveBaseUrl}/en/embed/sync?${t.toString()}`;
230
268
  }
231
269
  // ── Private: message handling ─────────────────────────────────────
232
270
  setupMessageListener() {
@@ -235,22 +273,30 @@ class g {
235
273
  const t = e.data;
236
274
  if (!(!t || typeof t != "object")) {
237
275
  if (t.source === "moment-live-embed" && t.type === "moment.embed.oauth.start") {
238
- const s = t;
276
+ const n = t;
239
277
  this.emitAnalytics("oauth.start", {
240
- provider: s.provider,
241
- teamSlug: s.teamSlug
242
- }), this.handleOAuthStart(s);
278
+ provider: n.provider,
279
+ teamSlug: n.teamSlug
280
+ }), this.handleOAuthStart(n);
281
+ return;
282
+ }
283
+ if (t.source === "moment-live-embed" && t.type === "moment.embed.resize") {
284
+ const n = typeof t.height == "number" ? t.height : 0;
285
+ if (n > 0 && this.iframe) {
286
+ const r = Math.round(window.innerHeight * 0.8);
287
+ this.iframe.style.height = `${Math.min(n, r)}px`;
288
+ }
243
289
  return;
244
290
  }
245
291
  if (t.source === "moment-live-embed" && t.type === "moment.embed.result") {
246
- const s = t;
247
- this.handleResult(s);
292
+ const n = t;
293
+ this.handleResult(n);
248
294
  }
249
295
  }
250
296
  }, window.addEventListener("message", this.messageHandler);
251
297
  }
252
298
  handleOAuthStart(e) {
253
- this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.popupBridge = new m({
299
+ this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.popupBridge = new f({
254
300
  liveBaseUrl: this.liveBaseUrl,
255
301
  liveOrigin: this.liveOrigin,
256
302
  iframeWindow: this.iframe?.contentWindow ?? null,
@@ -302,8 +348,8 @@ class g {
302
348
  if (this.closeTimer && (clearTimeout(this.closeTimer), this.closeTimer = null), this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.messageHandler && (window.removeEventListener("message", this.messageHandler), this.messageHandler = null), this.overlay) {
303
349
  const { _escHandler: e, _focusTrapHandler: t } = this.overlay;
304
350
  e && document.removeEventListener("keydown", e);
305
- const s = this.overlay.firstElementChild;
306
- s && t && s.removeEventListener("keydown", t), this.overlay.remove(), this.overlay = null;
351
+ const n = this.overlay.firstElementChild;
352
+ n && t && n.removeEventListener("keydown", t), this.overlay.remove(), this.overlay = null;
307
353
  }
308
354
  this.iframe = null, this.activePayload = null, this.didManageBodyOverflow && (document.body.style.overflow = this.previousBodyOverflow, this.didManageBodyOverflow = !1), this.previousFocusedElement && typeof this.previousFocusedElement.focus == "function" && this.previousFocusedElement.focus(), this.previousFocusedElement = null;
309
355
  }
@@ -316,9 +362,9 @@ class g {
316
362
  });
317
363
  }
318
364
  }
319
- function f(n) {
365
+ function w(o) {
320
366
  const e = document.createElement("button");
321
- return e.type = "button", e.classList.add("moment-sync-trigger"), n.className && n.className.split(" ").forEach((t) => {
367
+ return e.type = "button", e.classList.add("moment-sync-trigger"), o.className && o.className.split(" ").forEach((t) => {
322
368
  t && e.classList.add(t);
323
369
  }), Object.assign(e.style, {
324
370
  backgroundColor: "#1c1917",
@@ -330,13 +376,13 @@ function f(n) {
330
376
  fontWeight: "500",
331
377
  cursor: "pointer",
332
378
  lineHeight: "1.4"
333
- }), e.setAttribute("data-moment-team-slug", n.teamSlug), n.externalEventId && e.setAttribute("data-external-event-id", n.externalEventId), n.listSlug && e.setAttribute("data-moment-list-slug", n.listSlug), n.triggerType && e.setAttribute("data-moment-trigger-type", n.triggerType), n.ids?.length && e.setAttribute("data-moment-ids", n.ids.join(",")), n.calendar && e.setAttribute("data-moment-calendar", n.calendar), e.textContent = n.label ?? "Add to Calendar", e;
379
+ }), e.setAttribute("data-moment-team-slug", o.teamSlug), o.momentSlug && e.setAttribute("data-moment-slug", o.momentSlug), o.listSlug && e.setAttribute("data-moment-list-slug", o.listSlug), o.triggerType && e.setAttribute("data-moment-trigger-type", o.triggerType), o.ids?.length && e.setAttribute("data-moment-ids", o.ids.join(",")), o.calendar && e.setAttribute("data-moment-calendar", o.calendar), e.textContent = o.label ?? "Add to Calendar", e;
334
380
  }
335
381
  if (typeof window < "u") {
336
- const n = window;
337
- n.MomentSdk = g, n.createMomentButton = f;
382
+ const o = window;
383
+ o.MomentSdk = y, o.createMomentButton = w;
338
384
  }
339
385
  export {
340
- g as MomentSdk,
341
- f as createMomentButton
386
+ y as MomentSdk,
387
+ w as createMomentButton
342
388
  };
@@ -5,7 +5,8 @@ import type { MomentTriggerType, CalendarProvider } from './types';
5
5
  */
6
6
  export declare function createMomentButton(options: {
7
7
  teamSlug: string;
8
- externalEventId?: string;
8
+ /** Brand-level moment slug. */
9
+ momentSlug?: string;
9
10
  listSlug?: string;
10
11
  triggerType?: MomentTriggerType;
11
12
  ids?: string[];
@@ -1,4 +1,12 @@
1
- export type MomentTriggerType = 'moment' | 'list' | 'schedule';
1
+ /**
2
+ * Subscription target type forwarded to the Live embed and ultimately mapped
3
+ * to the backend `subscriptionType`.
4
+ *
5
+ * - `moment` → subscribe to one or more specific moments
6
+ * - `list` → subscribe to a curated list of moments
7
+ * - `team` → subscribe to a team / brand schedule (all published moments)
8
+ */
9
+ export type MomentTriggerType = 'moment' | 'list' | 'team';
2
10
  export type CalendarProvider = 'google' | 'outlook';
3
11
  export interface MomentSdkInitOptions {
4
12
  /** CSS selector for trigger elements. Default: ".moment-sync-trigger" */
@@ -12,14 +20,29 @@ export interface MomentSdkInitOptions {
12
20
  /** Optional analytics callback for tracking embed events. */
13
21
  onAnalytics?: (event: MomentAnalyticsEvent) => void;
14
22
  }
23
+ /**
24
+ * Payload accepted by `MomentSdk.open()` and parsed from trigger element
25
+ * `data-moment-*` attributes.
26
+ *
27
+ * Required fields by `triggerType`:
28
+ * - `moment` → `teamSlug` plus EITHER `momentSlug` (brand-level moment slug)
29
+ * OR `ids`
30
+ * - `list` → `teamSlug` plus `listSlug` (`ids` not required — list resolves
31
+ * to a single list-level subscription)
32
+ * - `team` → `teamSlug` only (resolves to the brand's team-level
33
+ * subscription; `listSlug`, `momentSlug`, and `ids` are ignored)
34
+ */
15
35
  export interface MomentSdkOpenPayload {
16
36
  teamSlug: string;
17
- externalEventId?: string;
37
+ /** Brand-level moment slug. */
38
+ momentSlug?: string;
18
39
  listSlug?: string;
19
40
  triggerType: MomentTriggerType;
20
41
  ids?: string[];
21
42
  calendar?: CalendarProvider;
22
43
  }
44
+ /** Backend subscription resource type that the embed will create */
45
+ export type MomentSubscriptionType = 'moment' | 'list' | 'team';
23
46
  /** Iframe → Parent: request to start OAuth via popup */
24
47
  export interface MomentOAuthStartPayload {
25
48
  source: 'moment-live-embed';
@@ -28,6 +51,14 @@ export interface MomentOAuthStartPayload {
28
51
  teamSlug: string;
29
52
  ids: string[];
30
53
  triggerType: MomentTriggerType;
54
+ /**
55
+ * Authoritative backend subscription type for `ids`.
56
+ * The iframe is the single source of truth: when present this should be
57
+ * forwarded verbatim to the popup so the popup does not need to re-derive
58
+ * it from `triggerType` (which would mis-handle cherry-picked moment IDs
59
+ * under a `list`/`team` trigger).
60
+ */
61
+ subscriptionType?: MomentSubscriptionType;
31
62
  returnOrigin: string;
32
63
  }
33
64
  /** Parent → Iframe: relay OAuth popup status */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momentco-ai/moment-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0-dev.13",
4
4
  "type": "module",
5
5
  "description": "Embeddable calendar sync widget for external team websites",
6
6
  "author": "Moment Co. <support@momentco.ai> (https://momentco.ai)",