@ekanos/cli 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/audiences.d.ts +5 -3
- package/dist/commands/audiences.js +6 -4
- package/dist/commands/audiences.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +5 -4
- package/dist/commands/scope-notice.js +22 -11
- package/dist/commands/scope-notice.js.map +1 -1
- package/dist/commands/teams-audience.d.ts +11 -2
- package/dist/commands/teams-audience.js +22 -7
- package/dist/commands/teams-audience.js.map +1 -1
- package/dist/commands/teams-lifecycle.js +8 -2
- package/dist/commands/teams-lifecycle.js.map +1 -1
- package/dist/experience/definition-checks.js +4 -1
- package/dist/experience/definition-checks.js.map +1 -1
- package/dist/experience/definition-shape.d.ts +2 -0
- package/dist/experience/definition-shape.js.map +1 -1
- package/dist/index.js +13 -9
- package/dist/index.js.map +1 -1
- package/dist/team-lifecycle-api.d.ts +30 -0
- package/dist/team-lifecycle-api.js +2 -0
- package/dist/team-lifecycle-api.js.map +1 -1
- package/dist/teams-api.js +29 -24
- package/dist/teams-api.js.map +1 -1
- package/package.json +2 -2
- package/templates/experience/package.json.tmpl +4 -4
- package/templates/package.json.tmpl +4 -4
|
@@ -14,9 +14,11 @@ export interface AudiencesArgs {
|
|
|
14
14
|
/**
|
|
15
15
|
* `audiences` — a Source's audiences, for its Source admin. An audience is a
|
|
16
16
|
* named set of the Source's products (with optional per-product widget and
|
|
17
|
-
* tool rules) that people see in the app
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* tool rules) that people see in the app. Each team is on one, its business
|
|
18
|
+
* type (`ekanos teams audience`), and every member is on their team's; the
|
|
19
|
+
* team's groups narrow it per person (`ekanos teams groups`). It replaces a
|
|
20
|
+
* product scope; `sources scopes` and `teams scope` keep working until the
|
|
21
|
+
* 2027-03-01 sunset.
|
|
20
22
|
*
|
|
21
23
|
* list every audience, its products and rules
|
|
22
24
|
* show <audience> one, in full
|
|
@@ -8,9 +8,11 @@ const USAGE = 'Run "ekanos audiences list", "ekanos audiences show <audience>",
|
|
|
8
8
|
/**
|
|
9
9
|
* `audiences` — a Source's audiences, for its Source admin. An audience is a
|
|
10
10
|
* named set of the Source's products (with optional per-product widget and
|
|
11
|
-
* tool rules) that people see in the app
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* tool rules) that people see in the app. Each team is on one, its business
|
|
12
|
+
* type (`ekanos teams audience`), and every member is on their team's; the
|
|
13
|
+
* team's groups narrow it per person (`ekanos teams groups`). It replaces a
|
|
14
|
+
* product scope; `sources scopes` and `teams scope` keep working until the
|
|
15
|
+
* 2027-03-01 sunset.
|
|
14
16
|
*
|
|
15
17
|
* list every audience, its products and rules
|
|
16
18
|
* show <audience> one, in full
|
|
@@ -62,7 +64,7 @@ export async function runAudiences(ctx, args) {
|
|
|
62
64
|
describeLines(audience),
|
|
63
65
|
]),
|
|
64
66
|
notes: [
|
|
65
|
-
'A person sees
|
|
67
|
+
'A person sees their team’s audience ("ekanos teams audience <team>"), narrowed by their groups ("ekanos teams groups list <team>").',
|
|
66
68
|
],
|
|
67
69
|
}));
|
|
68
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audiences.js","sourceRoot":"","sources":["../../src/commands/audiences.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAW,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AActC,MAAM,KAAK,GACT,sPAAsP,CAAC;AAIzP;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAe,EACf,IAAmB;;IAEnB,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC5D,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,UAAU,CAAC,iCAAiC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,UAAU,CAAC,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,wBAAwB,OAAO,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,EAAE,CAAC;IAC7B,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,UAAU,CACd,IAAI,KAAK,QAAQ;YACf,CAAC,CAAC,gCAAgC;YAClC,CAAC,CAAC,aAAa,IAAI,sCAAsC,EAC3D,KAAK,CACN,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,OAAC,IAAI,CAAC,KAAK,mCAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,GAAG,GAAG,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;QAC3D,UAAU,EAAE,IAAI,CAAC,GAAG;KACrB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE/B,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACvC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CACvC,CAAC;QACF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;gBACZ,KAAK,EAAE,mBAAmB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;gBAC5C,KAAK,EAAE,CAAC,4DAA4D,CAAC;aACtE,CAAC,CACH,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;YACZ,KAAK,EAAE,gBAAgB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YACzC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAsB,EAAE,CAAC;gBACzD,QAAQ,CAAC,IAAI;gBACb,aAAa,CAAC,QAAQ,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,uGAAuG;aACxG;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACxC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,CAAC,CAC3D,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,KAAK,GAC1B,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CACjE,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,6DACR,IAAI,EAAE,IAAK,IACR,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;YACpC,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,WAAW,EAAE;YAC5C,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;YAClE,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE;YACrC,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAC9C,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,OAAO,GAC5B,cAAc,CACZ,GAAG,CAAC,EAAE,EACN,OAAO,CAAC,QAAQ,EAChB,WAAW,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CACnC,CACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,CAAC,CAC3D,CAAC;IACF,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAChC,MAAM,IAAI,+DACL,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACtD,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;QACjC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;QACpC,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;QACjC,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,WAAW,EAAE;QAC5C,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;IACF,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,QAAQ,GAAG,UAAU,CACxB,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,+BAC/B,IAAI,EAAE,OAAO,CAAC,IAAI,IACf,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC3D,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC9D,CAAC,EACH,KAAK,CACN,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,UAAU,CACd,oBAAoB,EACpB,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAC,IAAI,CAAC,QAAQ,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;QAC3B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC,CAAC,EAAE,CAAC;IACP,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,iBAAiB,CACrB,GAAG,MAAM,CAAC,IAAI,yBAAyB,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,cAAc,EAC3K,2CAA2C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,QAAQ,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,EAAE,IAAI,CAAC,CACnE,CAAC;IACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,OAAO,GAC5B,cAAc,CACZ,GAAG,CAAC,EAAE,EACN,OAAO,CAAC,QAAQ,EAChB,WAAW,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAClC;QACE,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KACzC,CACF,CACF,CAAC;AACJ,CAAC;AAaD,SAAS,SAAS,CAChB,KAAkD;IAElD,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE,CAC3B,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,GAAG,CAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACzB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;gBACzB,CAAC,CAAC,CAAC,KAAK,CAAC;gBACT,CAAC,CAAC,EAAE,CAAC;IACX,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAClC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,SAAS,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI;QACjC,WAAW,EACT,OAAO,KAAK,CAAC,cAAc,CAAC,KAAK,SAAS;YACxC,CAAC,CAAE,KAAK,CAAC,cAAc,CAAa;YACpC,CAAC,CAAC,SAAS;QACf,QAAQ,EACN,QAAQ,KAAK,SAAS;YACpB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ,KAAK,MAAM;gBACnB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,QAAQ;qBACL,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;qBACxC,MAAM,CAAC,OAAO,CAAC;QAC1B,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,SAAS,OAAO,CAAC,IAAY,EAAE,MAAgB;IAC7C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxE,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,UAAU,CACd,KAAK,IAAI,yCAAyC,KAAK,KAAK,EAC5D,UAAU,IAAI,WAAW,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,gCAAgC,CAC/G,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,CACP,IAAI,EACJ,KAAK;aACF,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;aACb,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,SAAS,UAAU,CAAC,IAAmB,EAAE,KAAoB;;IAC3D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,KAAK,SAAG,KAAK,CAAC,QAAQ,mCAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAe,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,qCACE,IAAI,IACD,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,SAAS,EAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC9D,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,SAAS,EAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACjE;IACJ,CAAC,CAAC,CAAC;IACH,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI;QAC1B,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC;QAC5B,CAAC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC;KAClB,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,UAAU,CACd,KAAK,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,UAAU,IAAI,sCAAsC,EACnG,oEAAoE,CACrE,CAAC;YACJ,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;;gBACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB;IACvC,MAAM,KAAK,GAAG;QACZ;YACE,QAAQ,CAAC,mBAAmB;gBAC1B,CAAC,CAAC,8BAA8B;gBAChC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;YAClD,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI;SACtD;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,KAAK,CAAC;KACf,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YAC1B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAChD,CAAC,CAAC,aAAa,CAClB,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,OAAqC;IACzD,MAAM,KAAK,GAAG;QACZ,OAAO,CAAC,SAAS;YACf,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;YACpD,CAAC,CAAC,IAAI;QACR,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KAC5E,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC;QACrB,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAC9C,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CACrB,EAAM,EACN,QAAkB,EAClB,KAAa,EACb,OAAO,GAA6B,EAAE;;IAEtC,OAAO,EAAE,CAAC,MAAM,CAAC;QACf,KAAK;QACL,IAAI,QAAE,OAAO,CAAC,IAAI,mCAAI,IAAI;QAC1B,IAAI,EAAE;YACJ,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC;YAC3B,GAAG,CAAC,QAAQ,CAAC,WAAW;gBACtB,CAAC,CAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAA6B;gBAChE,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;YACrE;gBACE,UAAU;gBACV,QAAQ,CAAC,mBAAmB;oBAC1B,CAAC,CAAC,6CAA6C;oBAC/C,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;wBAC5B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC;wBACrC,CAAC,CAAC,MAAM;aACb;SACF;QACD,KAAK,EAAE;YACL,4FAA4F;SAC7F;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AAC7D,CAAC","sourcesContent":["import type {\n Audience,\n AudienceCreateRequest,\n AudienceUpdateRequest,\n} from '@ekanos/integration-schema';\n\nimport { requireSession, resolveAuthEnvironment } from '../auth/session';\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport {\n createAudience,\n listAudiences,\n showAudience,\n updateAudience,\n} from '../teams-api';\nimport { type Ui, pluralize } from '../ui';\nimport { TeamsClient } from './teams';\n\nexport interface AudiencesArgs {\n host?: string;\n source?: string;\n /** `list`, `show <audience>`, `create <name>`, `set <audience>`. */\n positionals: readonly string[];\n yes: boolean;\n /** `--products`, `--widgets`, `--tools`, `--name`, `--description` … */\n flags?: Record<string, string | boolean | string[]>;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\nconst USAGE =\n 'Run \"ekanos audiences list\", \"ekanos audiences show <audience>\", \"ekanos audiences create <name> [--products a,b | --all-entitled]\" or \"ekanos audiences set <audience> [--products a,b] [--widgets <product>=<id>,…] [--tools <product>=<name>,…]\".';\n\ntype ProductRule = { slug: string; widgetIds?: string[]; toolNames?: string[] };\n\n/**\n * `audiences` — a Source's audiences, for its Source admin. An audience is a\n * named set of the Source's products (with optional per-product widget and\n * tool rules) that people see in the app: each team member holds one, their\n * own else their team's default (`ekanos teams audience`). It replaces a\n * product scope; `sources scopes` and `teams scope` keep working until 0.20.\n *\n * list every audience, its products and rules\n * show <audience> one, in full\n * create <name> … --products a,b | --all-entitled, --description,\n * --default, --widgets <product>=<id>,…,\n * --tools <product>=<name>,…\n * set <audience> … the same flags, plus --name; --products\n * replaces the product set (rules of kept\n * products stay unless re-stated). Dropping a\n * product needs --yes.\n */\nexport async function runAudiences(\n ctx: CliContext,\n args: AudiencesArgs,\n): Promise<ExitCode> {\n const [verb = 'list', rawName, ...extra] = args.positionals;\n if (!['list', 'show', 'create', 'set'].includes(verb)) {\n throw usageError(`Unknown audiences subcommand \"${verb}\".`, USAGE);\n }\n if (extra.length > 0) {\n throw usageError(`Unexpected argument \"${extra[0]}\".`, USAGE);\n }\n if (verb === 'list' && rawName) {\n throw usageError(`Unexpected argument \"${rawName}\".`, USAGE);\n }\n const name = rawName?.trim();\n if (verb !== 'list' && !name) {\n throw usageError(\n verb === 'create'\n ? 'audiences create needs a name.'\n : `audiences ${verb} needs an audience (its name or id).`,\n USAGE,\n );\n }\n const flags = readFlags(args.flags ?? {});\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n const client = new TeamsClient(env, resolved.session);\n const source = resolved.source;\n\n if (verb === 'list') {\n const list = await client.call((token) =>\n listAudiences(env.host, token, source),\n );\n if (list.audiences.length === 0) {\n return ctx.succeed(\n { host: env.host, ...list },\n ctx.ui.result({\n title: `No audiences on ${list.source.slug}`,\n notes: [`\"ekanos audiences create <name> --products a,b\" makes one.`],\n }),\n );\n }\n return ctx.succeed(\n { host: env.host, ...list },\n ctx.ui.result({\n title: `Audiences on ${list.source.slug}`,\n rows: list.audiences.map((audience): [string, string[]] => [\n audience.name,\n describeLines(audience),\n ]),\n notes: [\n 'A person sees the products of their own audience, else their team’s (\"ekanos teams audience <team>\").',\n ],\n }),\n );\n }\n\n if (verb === 'show') {\n const shown = await client.call((token) =>\n showAudience(env.host, token, { source, audience: name! }),\n );\n return ctx.succeed(\n { host: env.host, ...shown },\n renderAudience(ctx.ui, shown.audience, `${shown.audience.name}`),\n );\n }\n\n if (verb === 'create') {\n const body: AudienceCreateRequest = {\n name: name!,\n ...(flags.description !== undefined\n ? { description: flags.description }\n : {}),\n ...(flags.isDefault ? { isDefault: true } : {}),\n ...(flags.allEntitled !== undefined\n ? { includesAllEntitled: flags.allEntitled }\n : {}),\n ...(flags.products || flags.widgets.size > 0 || flags.tools.size > 0\n ? { products: applyRules([], flags) }\n : {}),\n };\n const created = await client.call((token) =>\n createAudience(env.host, token, source, body),\n );\n return ctx.succeed(\n { host: env.host, ...created },\n renderAudience(\n ctx.ui,\n created.audience,\n `Created ${created.audience.name}`,\n ),\n );\n }\n\n const current = await client.call((token) =>\n showAudience(env.host, token, { source, audience: name! }),\n );\n const before = current.audience;\n const body: AudienceUpdateRequest = {\n ...(flags.name !== undefined ? { name: flags.name } : {}),\n ...(flags.description !== undefined\n ? { description: flags.description }\n : {}),\n ...(flags.isDefault ? { isDefault: true } : {}),\n ...(flags.allEntitled !== undefined\n ? { includesAllEntitled: flags.allEntitled }\n : {}),\n };\n if (flags.products || flags.widgets.size > 0 || flags.tools.size > 0) {\n body.products = applyRules(\n before.products.map((product) => ({\n slug: product.slug,\n ...(product.widgetIds ? { widgetIds: product.widgetIds } : {}),\n ...(product.toolNames ? { toolNames: product.toolNames } : {}),\n })),\n flags,\n );\n }\n if (Object.keys(body).length === 0) {\n throw usageError(\n 'Nothing to change.',\n 'Pass --products, --widgets, --tools, --name, --description, --default or --all-entitled.',\n );\n }\n\n const kept = new Set((body.products ?? []).map((product) => product.slug));\n const dropped = body.products\n ? before.products.filter((product) => !kept.has(product.slug))\n : [];\n if (dropped.length > 0 && !args.yes) {\n throw invalidStateError(\n `${before.name} would no longer show ${dropped.map((product) => product.slug).join(', ')}: everyone on it stops seeing ${dropped.length === 1 ? 'it' : 'them'} in the app.`,\n `Re-run with --yes: ekanos audiences set ${quote(before.name)} … --source ${source} --yes`,\n );\n }\n\n const updated = await client.call((token) =>\n updateAudience(env.host, token, { source, audience: name! }, body),\n );\n return ctx.succeed(\n { host: env.host, ...updated },\n renderAudience(\n ctx.ui,\n updated.audience,\n `Updated ${updated.audience.name}`,\n {\n tone: dropped.length > 0 ? 'warn' : 'ok',\n },\n ),\n );\n}\n\ninterface AudienceFlags {\n name?: string;\n description?: string;\n isDefault: boolean;\n allEntitled?: boolean;\n /** Slugs, in the order given; absent when the flag was not passed. */\n products?: string[];\n widgets: Map<string, string[]>;\n tools: Map<string, string[]>;\n}\n\nfunction readFlags(\n flags: Record<string, string | boolean | string[]>,\n): AudienceFlags {\n const text = (key: string) =>\n typeof flags[key] === 'string' ? (flags[key] as string) : undefined;\n const list = (key: string) => {\n const value = flags[key];\n return Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? [value]\n : [];\n };\n\n const products = text('products');\n return {\n name: text('name'),\n description: text('description'),\n isDefault: flags.default === true,\n allEntitled:\n typeof flags['all-entitled'] === 'boolean'\n ? (flags['all-entitled'] as boolean)\n : undefined,\n products:\n products === undefined\n ? undefined\n : products === 'none'\n ? []\n : products\n .split(',')\n .map((slug) => slug.trim().toLowerCase())\n .filter(Boolean),\n widgets: ruleMap('widgets', list('widgets')),\n tools: ruleMap('tools', list('tools')),\n };\n}\n\n/** `linear=w1,w2` per product; `linear=` clears the rule (all of them). */\nfunction ruleMap(flag: string, values: string[]): Map<string, string[]> {\n const rules = new Map<string, string[]>();\n for (const value of values) {\n const at = value.indexOf('=');\n const slug = (at < 0 ? value : value.slice(0, at)).trim().toLowerCase();\n if (!slug || at < 0) {\n throw usageError(\n `--${flag} takes <product>=<name>,<name>… (got \"${value}\").`,\n `e.g. --${flag} linear=${flag === 'widgets' ? 'linear-issues' : 'create_issue'}; \"<product>=\" lifts the rule.`,\n );\n }\n rules.set(\n slug,\n value\n .slice(at + 1)\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean),\n );\n }\n return rules;\n}\n\n/** The product set after `--products` and the widget and tool rules. */\nfunction applyRules(base: ProductRule[], flags: AudienceFlags): ProductRule[] {\n const known = new Map(base.map((product) => [product.slug, product]));\n const slugs = flags.products ?? base.map((product) => product.slug);\n\n const products = slugs.map((slug): ProductRule => {\n const existing = known.get(slug);\n return {\n slug,\n ...(existing?.widgetIds ? { widgetIds: existing.widgetIds } : {}),\n ...(existing?.toolNames ? { toolNames: existing.toolNames } : {}),\n };\n });\n for (const [kind, rules] of [\n ['widgetIds', flags.widgets],\n ['toolNames', flags.tools],\n ] as const) {\n for (const [slug, names] of rules) {\n const product = products.find((entry) => entry.slug === slug);\n if (!product) {\n throw usageError(\n `--${kind === 'widgetIds' ? 'widgets' : 'tools'} names ${slug}, which the audience would not show.`,\n 'Add it with --products, or name a product that is in the audience.',\n );\n }\n if (names.length > 0) product[kind] = names;\n else delete product[kind];\n }\n }\n return products;\n}\n\nfunction describeLines(audience: Audience): string[] {\n const lines = [\n [\n audience.includesAllEntitled\n ? 'every product the Source has'\n : pluralize(audience.products.length, 'product'),\n audience.isDefault ? 'given to every new team' : null,\n ]\n .filter(Boolean)\n .join(' · '),\n ];\n if (!audience.includesAllEntitled) {\n lines.push(\n audience.products.length > 0\n ? audience.products.map(productWords).join(', ')\n : 'no products',\n );\n }\n return lines;\n}\n\nfunction productWords(product: Audience['products'][number]): string {\n const rules = [\n product.widgetIds\n ? `${pluralize(product.widgetIds.length, 'widget')}`\n : null,\n product.toolNames ? `${pluralize(product.toolNames.length, 'tool')}` : null,\n ].filter(Boolean);\n return rules.length > 0\n ? `${product.slug} (only ${rules.join(', ')})`\n : product.slug;\n}\n\nfunction renderAudience(\n ui: Ui,\n audience: Audience,\n title: string,\n options: { tone?: 'ok' | 'warn' } = {},\n): string {\n return ui.result({\n title,\n tone: options.tone ?? 'ok',\n rows: [\n ['Audience', audience.name],\n ...(audience.description\n ? ([['About', audience.description]] as Array<[string, string]>)\n : []),\n ['Default', audience.isDefault ? 'yes, new teams start on it' : 'no'],\n [\n 'Products',\n audience.includesAllEntitled\n ? 'every product the Source has, now and later'\n : audience.products.length > 0\n ? audience.products.map(productWords)\n : 'none',\n ],\n ],\n notes: [\n 'Teams and members are put on an audience with \"ekanos teams audience <team> [<audience>]\".',\n ],\n });\n}\n\nfunction quote(name: string): string {\n return /^[A-Za-z0-9._-]+$/.test(name) ? name : `\"${name}\"`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"audiences.js","sourceRoot":"","sources":["../../src/commands/audiences.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAW,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AActC,MAAM,KAAK,GACT,sPAAsP,CAAC;AAIzP;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAe,EACf,IAAmB;;IAEnB,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC5D,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,UAAU,CAAC,iCAAiC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,UAAU,CAAC,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,wBAAwB,OAAO,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,EAAE,CAAC;IAC7B,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,UAAU,CACd,IAAI,KAAK,QAAQ;YACf,CAAC,CAAC,gCAAgC;YAClC,CAAC,CAAC,aAAa,IAAI,sCAAsC,EAC3D,KAAK,CACN,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,OAAC,IAAI,CAAC,KAAK,mCAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,GAAG,GAAG,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;QAC3D,UAAU,EAAE,IAAI,CAAC,GAAG;KACrB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE/B,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACvC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CACvC,CAAC;QACF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;gBACZ,KAAK,EAAE,mBAAmB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;gBAC5C,KAAK,EAAE,CAAC,4DAA4D,CAAC;aACtE,CAAC,CACH,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;YACZ,KAAK,EAAE,gBAAgB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YACzC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAsB,EAAE,CAAC;gBACzD,QAAQ,CAAC,IAAI;gBACb,aAAa,CAAC,QAAQ,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,qIAAqI;aACtI;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACxC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,CAAC,CAC3D,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,KAAK,GAC1B,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CACjE,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,6DACR,IAAI,EAAE,IAAK,IACR,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;YACpC,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,WAAW,EAAE;YAC5C,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;YAClE,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE;YACrC,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAC9C,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,OAAO,GAC5B,cAAc,CACZ,GAAG,CAAC,EAAE,EACN,OAAO,CAAC,QAAQ,EAChB,WAAW,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CACnC,CACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,CAAC,CAC3D,CAAC;IACF,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAChC,MAAM,IAAI,+DACL,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACtD,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;QACjC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;QACpC,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;QACjC,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,WAAW,EAAE;QAC5C,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;IACF,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,QAAQ,GAAG,UAAU,CACxB,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,+BAC/B,IAAI,EAAE,OAAO,CAAC,IAAI,IACf,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC3D,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC9D,CAAC,EACH,KAAK,CACN,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,UAAU,CACd,oBAAoB,EACpB,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAC,IAAI,CAAC,QAAQ,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;QAC3B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC,CAAC,EAAE,CAAC;IACP,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,iBAAiB,CACrB,GAAG,MAAM,CAAC,IAAI,yBAAyB,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,cAAc,EAC3K,2CAA2C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,QAAQ,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1C,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAK,EAAE,EAAE,IAAI,CAAC,CACnE,CAAC;IACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,OAAO,GAC5B,cAAc,CACZ,GAAG,CAAC,EAAE,EACN,OAAO,CAAC,QAAQ,EAChB,WAAW,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAClC;QACE,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KACzC,CACF,CACF,CAAC;AACJ,CAAC;AAaD,SAAS,SAAS,CAChB,KAAkD;IAElD,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE,CAC3B,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,GAAG,CAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACzB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;gBACzB,CAAC,CAAC,CAAC,KAAK,CAAC;gBACT,CAAC,CAAC,EAAE,CAAC;IACX,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAClC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,SAAS,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI;QACjC,WAAW,EACT,OAAO,KAAK,CAAC,cAAc,CAAC,KAAK,SAAS;YACxC,CAAC,CAAE,KAAK,CAAC,cAAc,CAAa;YACpC,CAAC,CAAC,SAAS;QACf,QAAQ,EACN,QAAQ,KAAK,SAAS;YACpB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ,KAAK,MAAM;gBACnB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,QAAQ;qBACL,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;qBACxC,MAAM,CAAC,OAAO,CAAC;QAC1B,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,SAAS,OAAO,CAAC,IAAY,EAAE,MAAgB;IAC7C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxE,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,UAAU,CACd,KAAK,IAAI,yCAAyC,KAAK,KAAK,EAC5D,UAAU,IAAI,WAAW,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,gCAAgC,CAC/G,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,CACP,IAAI,EACJ,KAAK;aACF,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;aACb,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,SAAS,UAAU,CAAC,IAAmB,EAAE,KAAoB;;IAC3D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,KAAK,SAAG,KAAK,CAAC,QAAQ,mCAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAe,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,qCACE,IAAI,IACD,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,SAAS,EAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC9D,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,SAAS,EAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACjE;IACJ,CAAC,CAAC,CAAC;IACH,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI;QAC1B,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC;QAC5B,CAAC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC;KAClB,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,UAAU,CACd,KAAK,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,UAAU,IAAI,sCAAsC,EACnG,oEAAoE,CACrE,CAAC;YACJ,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;;gBACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB;IACvC,MAAM,KAAK,GAAG;QACZ;YACE,QAAQ,CAAC,mBAAmB;gBAC1B,CAAC,CAAC,8BAA8B;gBAChC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;YAClD,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI;SACtD;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,KAAK,CAAC;KACf,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YAC1B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAChD,CAAC,CAAC,aAAa,CAClB,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,OAAqC;IACzD,MAAM,KAAK,GAAG;QACZ,OAAO,CAAC,SAAS;YACf,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;YACpD,CAAC,CAAC,IAAI;QACR,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KAC5E,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC;QACrB,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAC9C,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CACrB,EAAM,EACN,QAAkB,EAClB,KAAa,EACb,OAAO,GAA6B,EAAE;;IAEtC,OAAO,EAAE,CAAC,MAAM,CAAC;QACf,KAAK;QACL,IAAI,QAAE,OAAO,CAAC,IAAI,mCAAI,IAAI;QAC1B,IAAI,EAAE;YACJ,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC;YAC3B,GAAG,CAAC,QAAQ,CAAC,WAAW;gBACtB,CAAC,CAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAA6B;gBAChE,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;YACrE;gBACE,UAAU;gBACV,QAAQ,CAAC,mBAAmB;oBAC1B,CAAC,CAAC,6CAA6C;oBAC/C,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;wBAC5B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC;wBACrC,CAAC,CAAC,MAAM;aACb;SACF;QACD,KAAK,EAAE;YACL,4FAA4F;SAC7F;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AAC7D,CAAC","sourcesContent":["import type {\n Audience,\n AudienceCreateRequest,\n AudienceUpdateRequest,\n} from '@ekanos/integration-schema';\n\nimport { requireSession, resolveAuthEnvironment } from '../auth/session';\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport {\n createAudience,\n listAudiences,\n showAudience,\n updateAudience,\n} from '../teams-api';\nimport { type Ui, pluralize } from '../ui';\nimport { TeamsClient } from './teams';\n\nexport interface AudiencesArgs {\n host?: string;\n source?: string;\n /** `list`, `show <audience>`, `create <name>`, `set <audience>`. */\n positionals: readonly string[];\n yes: boolean;\n /** `--products`, `--widgets`, `--tools`, `--name`, `--description` … */\n flags?: Record<string, string | boolean | string[]>;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\nconst USAGE =\n 'Run \"ekanos audiences list\", \"ekanos audiences show <audience>\", \"ekanos audiences create <name> [--products a,b | --all-entitled]\" or \"ekanos audiences set <audience> [--products a,b] [--widgets <product>=<id>,…] [--tools <product>=<name>,…]\".';\n\ntype ProductRule = { slug: string; widgetIds?: string[]; toolNames?: string[] };\n\n/**\n * `audiences` — a Source's audiences, for its Source admin. An audience is a\n * named set of the Source's products (with optional per-product widget and\n * tool rules) that people see in the app. Each team is on one, its business\n * type (`ekanos teams audience`), and every member is on their team's; the\n * team's groups narrow it per person (`ekanos teams groups`). It replaces a\n * product scope; `sources scopes` and `teams scope` keep working until the\n * 2027-03-01 sunset.\n *\n * list every audience, its products and rules\n * show <audience> one, in full\n * create <name> … --products a,b | --all-entitled, --description,\n * --default, --widgets <product>=<id>,…,\n * --tools <product>=<name>,…\n * set <audience> … the same flags, plus --name; --products\n * replaces the product set (rules of kept\n * products stay unless re-stated). Dropping a\n * product needs --yes.\n */\nexport async function runAudiences(\n ctx: CliContext,\n args: AudiencesArgs,\n): Promise<ExitCode> {\n const [verb = 'list', rawName, ...extra] = args.positionals;\n if (!['list', 'show', 'create', 'set'].includes(verb)) {\n throw usageError(`Unknown audiences subcommand \"${verb}\".`, USAGE);\n }\n if (extra.length > 0) {\n throw usageError(`Unexpected argument \"${extra[0]}\".`, USAGE);\n }\n if (verb === 'list' && rawName) {\n throw usageError(`Unexpected argument \"${rawName}\".`, USAGE);\n }\n const name = rawName?.trim();\n if (verb !== 'list' && !name) {\n throw usageError(\n verb === 'create'\n ? 'audiences create needs a name.'\n : `audiences ${verb} needs an audience (its name or id).`,\n USAGE,\n );\n }\n const flags = readFlags(args.flags ?? {});\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n const client = new TeamsClient(env, resolved.session);\n const source = resolved.source;\n\n if (verb === 'list') {\n const list = await client.call((token) =>\n listAudiences(env.host, token, source),\n );\n if (list.audiences.length === 0) {\n return ctx.succeed(\n { host: env.host, ...list },\n ctx.ui.result({\n title: `No audiences on ${list.source.slug}`,\n notes: [`\"ekanos audiences create <name> --products a,b\" makes one.`],\n }),\n );\n }\n return ctx.succeed(\n { host: env.host, ...list },\n ctx.ui.result({\n title: `Audiences on ${list.source.slug}`,\n rows: list.audiences.map((audience): [string, string[]] => [\n audience.name,\n describeLines(audience),\n ]),\n notes: [\n 'A person sees their team’s audience (\"ekanos teams audience <team>\"), narrowed by their groups (\"ekanos teams groups list <team>\").',\n ],\n }),\n );\n }\n\n if (verb === 'show') {\n const shown = await client.call((token) =>\n showAudience(env.host, token, { source, audience: name! }),\n );\n return ctx.succeed(\n { host: env.host, ...shown },\n renderAudience(ctx.ui, shown.audience, `${shown.audience.name}`),\n );\n }\n\n if (verb === 'create') {\n const body: AudienceCreateRequest = {\n name: name!,\n ...(flags.description !== undefined\n ? { description: flags.description }\n : {}),\n ...(flags.isDefault ? { isDefault: true } : {}),\n ...(flags.allEntitled !== undefined\n ? { includesAllEntitled: flags.allEntitled }\n : {}),\n ...(flags.products || flags.widgets.size > 0 || flags.tools.size > 0\n ? { products: applyRules([], flags) }\n : {}),\n };\n const created = await client.call((token) =>\n createAudience(env.host, token, source, body),\n );\n return ctx.succeed(\n { host: env.host, ...created },\n renderAudience(\n ctx.ui,\n created.audience,\n `Created ${created.audience.name}`,\n ),\n );\n }\n\n const current = await client.call((token) =>\n showAudience(env.host, token, { source, audience: name! }),\n );\n const before = current.audience;\n const body: AudienceUpdateRequest = {\n ...(flags.name !== undefined ? { name: flags.name } : {}),\n ...(flags.description !== undefined\n ? { description: flags.description }\n : {}),\n ...(flags.isDefault ? { isDefault: true } : {}),\n ...(flags.allEntitled !== undefined\n ? { includesAllEntitled: flags.allEntitled }\n : {}),\n };\n if (flags.products || flags.widgets.size > 0 || flags.tools.size > 0) {\n body.products = applyRules(\n before.products.map((product) => ({\n slug: product.slug,\n ...(product.widgetIds ? { widgetIds: product.widgetIds } : {}),\n ...(product.toolNames ? { toolNames: product.toolNames } : {}),\n })),\n flags,\n );\n }\n if (Object.keys(body).length === 0) {\n throw usageError(\n 'Nothing to change.',\n 'Pass --products, --widgets, --tools, --name, --description, --default or --all-entitled.',\n );\n }\n\n const kept = new Set((body.products ?? []).map((product) => product.slug));\n const dropped = body.products\n ? before.products.filter((product) => !kept.has(product.slug))\n : [];\n if (dropped.length > 0 && !args.yes) {\n throw invalidStateError(\n `${before.name} would no longer show ${dropped.map((product) => product.slug).join(', ')}: everyone on it stops seeing ${dropped.length === 1 ? 'it' : 'them'} in the app.`,\n `Re-run with --yes: ekanos audiences set ${quote(before.name)} … --source ${source} --yes`,\n );\n }\n\n const updated = await client.call((token) =>\n updateAudience(env.host, token, { source, audience: name! }, body),\n );\n return ctx.succeed(\n { host: env.host, ...updated },\n renderAudience(\n ctx.ui,\n updated.audience,\n `Updated ${updated.audience.name}`,\n {\n tone: dropped.length > 0 ? 'warn' : 'ok',\n },\n ),\n );\n}\n\ninterface AudienceFlags {\n name?: string;\n description?: string;\n isDefault: boolean;\n allEntitled?: boolean;\n /** Slugs, in the order given; absent when the flag was not passed. */\n products?: string[];\n widgets: Map<string, string[]>;\n tools: Map<string, string[]>;\n}\n\nfunction readFlags(\n flags: Record<string, string | boolean | string[]>,\n): AudienceFlags {\n const text = (key: string) =>\n typeof flags[key] === 'string' ? (flags[key] as string) : undefined;\n const list = (key: string) => {\n const value = flags[key];\n return Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? [value]\n : [];\n };\n\n const products = text('products');\n return {\n name: text('name'),\n description: text('description'),\n isDefault: flags.default === true,\n allEntitled:\n typeof flags['all-entitled'] === 'boolean'\n ? (flags['all-entitled'] as boolean)\n : undefined,\n products:\n products === undefined\n ? undefined\n : products === 'none'\n ? []\n : products\n .split(',')\n .map((slug) => slug.trim().toLowerCase())\n .filter(Boolean),\n widgets: ruleMap('widgets', list('widgets')),\n tools: ruleMap('tools', list('tools')),\n };\n}\n\n/** `linear=w1,w2` per product; `linear=` clears the rule (all of them). */\nfunction ruleMap(flag: string, values: string[]): Map<string, string[]> {\n const rules = new Map<string, string[]>();\n for (const value of values) {\n const at = value.indexOf('=');\n const slug = (at < 0 ? value : value.slice(0, at)).trim().toLowerCase();\n if (!slug || at < 0) {\n throw usageError(\n `--${flag} takes <product>=<name>,<name>… (got \"${value}\").`,\n `e.g. --${flag} linear=${flag === 'widgets' ? 'linear-issues' : 'create_issue'}; \"<product>=\" lifts the rule.`,\n );\n }\n rules.set(\n slug,\n value\n .slice(at + 1)\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean),\n );\n }\n return rules;\n}\n\n/** The product set after `--products` and the widget and tool rules. */\nfunction applyRules(base: ProductRule[], flags: AudienceFlags): ProductRule[] {\n const known = new Map(base.map((product) => [product.slug, product]));\n const slugs = flags.products ?? base.map((product) => product.slug);\n\n const products = slugs.map((slug): ProductRule => {\n const existing = known.get(slug);\n return {\n slug,\n ...(existing?.widgetIds ? { widgetIds: existing.widgetIds } : {}),\n ...(existing?.toolNames ? { toolNames: existing.toolNames } : {}),\n };\n });\n for (const [kind, rules] of [\n ['widgetIds', flags.widgets],\n ['toolNames', flags.tools],\n ] as const) {\n for (const [slug, names] of rules) {\n const product = products.find((entry) => entry.slug === slug);\n if (!product) {\n throw usageError(\n `--${kind === 'widgetIds' ? 'widgets' : 'tools'} names ${slug}, which the audience would not show.`,\n 'Add it with --products, or name a product that is in the audience.',\n );\n }\n if (names.length > 0) product[kind] = names;\n else delete product[kind];\n }\n }\n return products;\n}\n\nfunction describeLines(audience: Audience): string[] {\n const lines = [\n [\n audience.includesAllEntitled\n ? 'every product the Source has'\n : pluralize(audience.products.length, 'product'),\n audience.isDefault ? 'given to every new team' : null,\n ]\n .filter(Boolean)\n .join(' · '),\n ];\n if (!audience.includesAllEntitled) {\n lines.push(\n audience.products.length > 0\n ? audience.products.map(productWords).join(', ')\n : 'no products',\n );\n }\n return lines;\n}\n\nfunction productWords(product: Audience['products'][number]): string {\n const rules = [\n product.widgetIds\n ? `${pluralize(product.widgetIds.length, 'widget')}`\n : null,\n product.toolNames ? `${pluralize(product.toolNames.length, 'tool')}` : null,\n ].filter(Boolean);\n return rules.length > 0\n ? `${product.slug} (only ${rules.join(', ')})`\n : product.slug;\n}\n\nfunction renderAudience(\n ui: Ui,\n audience: Audience,\n title: string,\n options: { tone?: 'ok' | 'warn' } = {},\n): string {\n return ui.result({\n title,\n tone: options.tone ?? 'ok',\n rows: [\n ['Audience', audience.name],\n ...(audience.description\n ? ([['About', audience.description]] as Array<[string, string]>)\n : []),\n ['Default', audience.isDefault ? 'yes, new teams start on it' : 'no'],\n [\n 'Products',\n audience.includesAllEntitled\n ? 'every product the Source has, now and later'\n : audience.products.length > 0\n ? audience.products.map(productWords)\n : 'none',\n ],\n ],\n notes: [\n 'Teams and members are put on an audience with \"ekanos teams audience <team> [<audience>]\".',\n ],\n });\n}\n\nfunction quote(name: string): string {\n return /^[A-Za-z0-9._-]+$/.test(name) ? name : `\"${name}\"`;\n}\n"]}
|
|
@@ -2,14 +2,15 @@ import type { TeamScopeState } from '@ekanos/integration-schema';
|
|
|
2
2
|
/**
|
|
3
3
|
* A product the CLI reports as ready for a team can still be hidden from the
|
|
4
4
|
* team in the app by the team's product scopes — the "Bronze" scope that
|
|
5
|
-
* hid Linear and Zendesk on a team whose setup read as done
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* hid Linear and Zendesk on a team whose setup read as done — or, once a
|
|
6
|
+
* Source's scopes are retired, by the team's audience (its business type).
|
|
7
|
+
* Wherever the CLI says a product is ready, it says this too, with the
|
|
8
|
+
* command that changes it.
|
|
8
9
|
*/
|
|
9
10
|
/**
|
|
10
11
|
* The one line `sources scopes` and `teams scope` print (to stderr, so JSON
|
|
11
12
|
* on stdout is unchanged): a scope is an audience now. Both commands keep
|
|
12
|
-
* their published behaviour until
|
|
13
|
+
* their published behaviour until the scope routes' 2027-03-01 sunset.
|
|
13
14
|
*/
|
|
14
15
|
export declare function scopeDeprecationNotice(replacement: string): string;
|
|
15
16
|
export interface ScopeFacts {
|
|
@@ -2,30 +2,41 @@ import { cli } from '../invocation.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* A product the CLI reports as ready for a team can still be hidden from the
|
|
4
4
|
* team in the app by the team's product scopes — the "Bronze" scope that
|
|
5
|
-
* hid Linear and Zendesk on a team whose setup read as done
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* hid Linear and Zendesk on a team whose setup read as done — or, once a
|
|
6
|
+
* Source's scopes are retired, by the team's audience (its business type).
|
|
7
|
+
* Wherever the CLI says a product is ready, it says this too, with the
|
|
8
|
+
* command that changes it.
|
|
8
9
|
*/
|
|
9
10
|
/**
|
|
10
11
|
* The one line `sources scopes` and `teams scope` print (to stderr, so JSON
|
|
11
12
|
* on stdout is unchanged): a scope is an audience now. Both commands keep
|
|
12
|
-
* their published behaviour until
|
|
13
|
+
* their published behaviour until the scope routes' 2027-03-01 sunset.
|
|
13
14
|
*/
|
|
14
15
|
export function scopeDeprecationNotice(replacement) {
|
|
15
|
-
return `Deprecated: product scopes are audiences now. Use "${cli()} ${replacement}"; this command keeps working until
|
|
16
|
+
return `Deprecated: product scopes are audiences now. Use "${cli()} ${replacement}"; this command keeps working until 2027-03-01.`;
|
|
16
17
|
}
|
|
17
18
|
/** "hidden by its product scope Bronze" — the problem, in words. */
|
|
18
19
|
export function scopeHiddenWords(scope) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// No scope held and still scoped: the team's audience (its business type)
|
|
21
|
+
// decides, which only a host whose scopes are retired reports.
|
|
22
|
+
if (scope.state === 'locked_out') {
|
|
23
|
+
return 'hidden from the team in the app: it holds none of the Source’s product scopes, and no audience';
|
|
24
|
+
}
|
|
25
|
+
if (scope.scopes.length === 0) {
|
|
26
|
+
return 'hidden from the team in the app by its audience';
|
|
27
|
+
}
|
|
28
|
+
return `hidden from the team in the app by its product scope${scope.scopes.length === 1 ? '' : 's'} ${scope.scopes.join(', ')}`;
|
|
22
29
|
}
|
|
23
30
|
/** The command that shows the product to the team. */
|
|
24
31
|
export function scopeFix(scope, target) {
|
|
25
|
-
const
|
|
26
|
-
if (scope.state === 'locked_out'
|
|
27
|
-
return `${
|
|
32
|
+
const audience = `${cli()} teams audience ${target.team} <audience> --source ${target.source}`;
|
|
33
|
+
if (scope.state === 'locked_out') {
|
|
34
|
+
return `${audience} (audiences and their products: ${cli()} audiences list --source ${target.source}; a host still on scopes: ${cli()} teams scope set ${target.team} <scope>)`;
|
|
28
35
|
}
|
|
36
|
+
if (scope.scopes.length === 0) {
|
|
37
|
+
return `"${cli()} teams audience ${target.team} --source ${target.source}" names its audience; add ${target.product} to it with "${cli()} audiences set <audience> --products …", or move the team: ${audience}`;
|
|
38
|
+
}
|
|
39
|
+
const set = `${cli()} teams scope set ${target.team} <scope> --source ${target.source}`;
|
|
29
40
|
return `${cli()} sources scopes add ${quote(scope.scopes[0])} ${target.product} --source ${target.source} (every team on ${scope.scopes[0]} then sees it; or move the team to a scope that has it: ${set})`;
|
|
30
41
|
}
|
|
31
42
|
/** The two lines `teams show` / `teams connect` print for a hidden product. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-notice.js","sourceRoot":"","sources":["../../src/commands/scope-notice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC
|
|
1
|
+
{"version":3,"file":"scope-notice.js","sourceRoot":"","sources":["../../src/commands/scope-notice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,OAAO,sDAAsD,GAAG,EAAE,IAAI,WAAW,iDAAiD,CAAC;AACrI,CAAC;AAOD,oEAAoE;AACpE,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,0EAA0E;IAC1E,+DAA+D;IAC/D,IAAI,KAAK,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,gGAAgG,CAAC;IAC1G,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,iDAAiD,CAAC;IAC3D,CAAC;IACD,OAAO,uDAAuD,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAClI,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,QAAQ,CACtB,KAAiB,EACjB,MAAyD;IAEzD,MAAM,QAAQ,GAAG,GAAG,GAAG,EAAE,mBAAmB,MAAM,CAAC,IAAI,wBAAwB,MAAM,CAAC,MAAM,EAAE,CAAC;IAC/F,IAAI,KAAK,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,GAAG,QAAQ,oCAAoC,GAAG,EAAE,4BAA4B,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,oBAAoB,MAAM,CAAC,IAAI,WAAW,CAAC;IACnL,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,GAAG,EAAE,mBAAmB,MAAM,CAAC,IAAI,aAAa,MAAM,CAAC,MAAM,6BAA6B,MAAM,CAAC,OAAO,gBAAgB,GAAG,EAAE,8DAA8D,QAAQ,EAAE,CAAC;IACnN,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,oBAAoB,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC;IACxF,OAAO,GAAG,GAAG,EAAE,uBAAuB,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI,MAAM,CAAC,OAAO,aAAa,MAAM,CAAC,MAAM,oBAAoB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,2DAA2D,GAAG,GAAG,CAAC;AAChN,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAC9B,KAAqD,EACrD,MAAyD;IAEzD,IAAI,EAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,CAAA;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO;QACL,KAAK,MAAM,CAAC,OAAO,OAAO,gBAAgB,CAAC,KAAK,CAAC,GAAG;QACpD,UAAU,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AAC7D,CAAC","sourcesContent":["import type { TeamScopeState } from '@ekanos/integration-schema';\n\nimport { cli } from '../invocation';\n\n/**\n * A product the CLI reports as ready for a team can still be hidden from the\n * team in the app by the team's product scopes — the \"Bronze\" scope that\n * hid Linear and Zendesk on a team whose setup read as done — or, once a\n * Source's scopes are retired, by the team's audience (its business type).\n * Wherever the CLI says a product is ready, it says this too, with the\n * command that changes it.\n */\n\n/**\n * The one line `sources scopes` and `teams scope` print (to stderr, so JSON\n * on stdout is unchanged): a scope is an audience now. Both commands keep\n * their published behaviour until the scope routes' 2027-03-01 sunset.\n */\nexport function scopeDeprecationNotice(replacement: string): string {\n return `Deprecated: product scopes are audiences now. Use \"${cli()} ${replacement}\"; this command keeps working until 2027-03-01.`;\n}\n\nexport interface ScopeFacts {\n state: TeamScopeState;\n scopes: string[];\n}\n\n/** \"hidden by its product scope Bronze\" — the problem, in words. */\nexport function scopeHiddenWords(scope: ScopeFacts): string {\n // No scope held and still scoped: the team's audience (its business type)\n // decides, which only a host whose scopes are retired reports.\n if (scope.state === 'locked_out') {\n return 'hidden from the team in the app: it holds none of the Source’s product scopes, and no audience';\n }\n if (scope.scopes.length === 0) {\n return 'hidden from the team in the app by its audience';\n }\n return `hidden from the team in the app by its product scope${scope.scopes.length === 1 ? '' : 's'} ${scope.scopes.join(', ')}`;\n}\n\n/** The command that shows the product to the team. */\nexport function scopeFix(\n scope: ScopeFacts,\n target: { team: string; product: string; source: string },\n): string {\n const audience = `${cli()} teams audience ${target.team} <audience> --source ${target.source}`;\n if (scope.state === 'locked_out') {\n return `${audience} (audiences and their products: ${cli()} audiences list --source ${target.source}; a host still on scopes: ${cli()} teams scope set ${target.team} <scope>)`;\n }\n if (scope.scopes.length === 0) {\n return `\"${cli()} teams audience ${target.team} --source ${target.source}\" names its audience; add ${target.product} to it with \"${cli()} audiences set <audience> --products …\", or move the team: ${audience}`;\n }\n const set = `${cli()} teams scope set ${target.team} <scope> --source ${target.source}`;\n return `${cli()} sources scopes add ${quote(scope.scopes[0]!)} ${target.product} --source ${target.source} (every team on ${scope.scopes[0]} then sees it; or move the team to a scope that has it: ${set})`;\n}\n\n/** The two lines `teams show` / `teams connect` print for a hidden product. */\nexport function scopeHiddenLines(\n scope: (ScopeFacts & { hidden: boolean }) | undefined,\n target: { team: string; product: string; source: string },\n): string[] {\n if (!scope?.hidden) return [];\n return [\n `! ${target.product} is ${scopeHiddenWords(scope)}.`,\n ` Fix: ${scopeFix(scope, target)}`,\n ];\n}\n\nfunction quote(name: string): string {\n return /^[A-Za-z0-9._-]+$/.test(name) ? name : `\"${name}\"`;\n}\n"]}
|
|
@@ -3,10 +3,19 @@ import type { ExitCode } from '../exit-codes.js';
|
|
|
3
3
|
import { type TeamsArgs } from './teams.js';
|
|
4
4
|
/**
|
|
5
5
|
* `teams audience <team> [<audience>] [--member <email> [--inherit]]` — the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* team's audience (its business type), which every member is on; their
|
|
7
|
+
* groups narrow it (`teams groups`). Without an audience it reads. Moving
|
|
8
8
|
* people to an audience that shows fewer products hides the difference from
|
|
9
9
|
* them in the app, so that needs `--yes`. `teams scope` is the deprecated
|
|
10
10
|
* form of this.
|
|
11
|
+
*
|
|
12
|
+
* `--member <email>` reads one person's. Setting it (`<audience>` or
|
|
13
|
+
* `--inherit`) is deprecated: a host on plan 258 refuses a per-person
|
|
14
|
+
* audience (`AUDIENCE_SET_ON_TEAM`), and an older host still takes it.
|
|
11
15
|
*/
|
|
12
16
|
export declare function runTeamAudience(ctx: CliContext, args: TeamsArgs, rest: readonly string[]): Promise<ExitCode>;
|
|
17
|
+
/**
|
|
18
|
+
* The one line a per-person audience write prints (to stderr, so JSON on
|
|
19
|
+
* stdout is unchanged) before it is sent.
|
|
20
|
+
*/
|
|
21
|
+
export declare function memberAudienceDeprecationNotice(team: string): string;
|
|
@@ -3,14 +3,18 @@ import { invalidStateError, usageError } from '../errors.js';
|
|
|
3
3
|
import { resolveSourceTarget } from '../source-target.js';
|
|
4
4
|
import { listAudiences, setMemberAudience, setTeamAudience, showMemberAudience, showTeamAudience, } from '../teams-api.js';
|
|
5
5
|
import { TeamsClient } from './teams.js';
|
|
6
|
-
const USAGE = 'Run "ekanos teams audience <team>" to read a team’s audience, "ekanos teams audience <team> <audience> [--yes]" to set it, or add --member <email>
|
|
6
|
+
const USAGE = 'Run "ekanos teams audience <team>" to read a team’s audience (its business type), "ekanos teams audience <team> <audience> [--yes]" to set it, or add --member <email> to read one person’s.';
|
|
7
7
|
/**
|
|
8
8
|
* `teams audience <team> [<audience>] [--member <email> [--inherit]]` — the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* team's audience (its business type), which every member is on; their
|
|
10
|
+
* groups narrow it (`teams groups`). Without an audience it reads. Moving
|
|
11
11
|
* people to an audience that shows fewer products hides the difference from
|
|
12
12
|
* them in the app, so that needs `--yes`. `teams scope` is the deprecated
|
|
13
13
|
* form of this.
|
|
14
|
+
*
|
|
15
|
+
* `--member <email>` reads one person's. Setting it (`<audience>` or
|
|
16
|
+
* `--inherit`) is deprecated: a host on plan 258 refuses a per-person
|
|
17
|
+
* audience (`AUDIENCE_SET_ON_TEAM`), and an older host still takes it.
|
|
14
18
|
*/
|
|
15
19
|
export async function runTeamAudience(ctx, args, rest) {
|
|
16
20
|
var _a, _b;
|
|
@@ -50,6 +54,10 @@ export async function runTeamAudience(ctx, args, rest) {
|
|
|
50
54
|
if (!audience && !inherit) {
|
|
51
55
|
return ctx.succeed(Object.assign({ host: env.host }, current), describeMember(ctx, current));
|
|
52
56
|
}
|
|
57
|
+
if (inherit && !current.isOverride) {
|
|
58
|
+
return ctx.succeed(Object.assign(Object.assign({ host: env.host }, current), { before: current.audience }), describeMember(ctx, current, current.audience));
|
|
59
|
+
}
|
|
60
|
+
ctx.warn(memberAudienceDeprecationNotice(team));
|
|
53
61
|
const next = inherit
|
|
54
62
|
? (await client.call((token) => showTeamAudience(env.host, token, target))).audience.id
|
|
55
63
|
: audience;
|
|
@@ -72,7 +80,7 @@ export async function runTeamAudience(ctx, args, rest) {
|
|
|
72
80
|
source,
|
|
73
81
|
from: current.audience,
|
|
74
82
|
to: audience,
|
|
75
|
-
who: `members of ${team}
|
|
83
|
+
who: `members of ${team}`,
|
|
76
84
|
yes: args.yes,
|
|
77
85
|
retry: `ekanos teams audience ${team} ${quote(audience)} --source ${source} --yes`,
|
|
78
86
|
});
|
|
@@ -109,7 +117,7 @@ function findAudience(audiences, ref) {
|
|
|
109
117
|
function describeTeam(ctx, result, before) {
|
|
110
118
|
var _a;
|
|
111
119
|
return ctx.ui.result({
|
|
112
|
-
title: `${result.team.slug}
|
|
120
|
+
title: `${result.team.slug} is on ${result.audience.name}`,
|
|
113
121
|
rows: [
|
|
114
122
|
['Audience', result.audience.name],
|
|
115
123
|
...(before !== undefined
|
|
@@ -117,7 +125,7 @@ function describeTeam(ctx, result, before) {
|
|
|
117
125
|
: []),
|
|
118
126
|
],
|
|
119
127
|
notes: [
|
|
120
|
-
|
|
128
|
+
`Every member is on it; their groups narrow it: "ekanos teams groups list ${result.team.slug}".`,
|
|
121
129
|
'"ekanos audiences show <audience>" lists what it shows.',
|
|
122
130
|
],
|
|
123
131
|
});
|
|
@@ -130,7 +138,7 @@ function describeMember(ctx, result, before) {
|
|
|
130
138
|
['Audience', result.audience.name],
|
|
131
139
|
[
|
|
132
140
|
'From',
|
|
133
|
-
result.isOverride ? 'their own' : `the ${result.team.slug}
|
|
141
|
+
result.isOverride ? 'their own' : `the ${result.team.slug} audience`,
|
|
134
142
|
],
|
|
135
143
|
...(before !== undefined
|
|
136
144
|
? [['Before', (_a = before === null || before === void 0 ? void 0 : before.name) !== null && _a !== void 0 ? _a : 'none']]
|
|
@@ -138,6 +146,13 @@ function describeMember(ctx, result, before) {
|
|
|
138
146
|
],
|
|
139
147
|
});
|
|
140
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* The one line a per-person audience write prints (to stderr, so JSON on
|
|
151
|
+
* stdout is unchanged) before it is sent.
|
|
152
|
+
*/
|
|
153
|
+
export function memberAudienceDeprecationNotice(team) {
|
|
154
|
+
return `Deprecated: a person’s access is set by the team’s audience and their groups. Hosts on the audiences model refuse this (AUDIENCE_SET_ON_TEAM); set the team’s with "ekanos teams audience ${team} <audience>", or add them to a group with "ekanos teams groups members add ${team} <group> <email>".`;
|
|
155
|
+
}
|
|
141
156
|
function quote(name) {
|
|
142
157
|
return /^[A-Za-z0-9._-]+$/.test(name) ? name : `"${name}"`;
|
|
143
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teams-audience.js","sourceRoot":"","sources":["../../src/commands/teams-audience.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Audience,\n AudienceRef,\n MemberAudience,\n TeamAudience,\n} from '@ekanos/integration-schema';\n\nimport { requireSession, resolveAuthEnvironment } from '../auth/session';\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport {\n listAudiences,\n setMemberAudience,\n setTeamAudience,\n showMemberAudience,\n showTeamAudience,\n} from '../teams-api';\nimport { TeamsClient, type TeamsArgs } from './teams';\n\nconst USAGE =\n 'Run \"ekanos teams audience <team>\" to read a team’s audience, \"ekanos teams audience <team> <audience> [--yes]\" to set it, or add --member <email> (with <audience>, or --inherit to clear it) for one person’s own.';\n\n/**\n * `teams audience <team> [<audience>] [--member <email> [--inherit]]` — the\n * audience a team starts its members on, and a member's own override of it\n * (a Source admin's only; audited). Without an audience it reads. Moving\n * people to an audience that shows fewer products hides the difference from\n * them in the app, so that needs `--yes`. `teams scope` is the deprecated\n * form of this.\n */\nexport async function runTeamAudience(\n ctx: CliContext,\n args: TeamsArgs,\n rest: readonly string[],\n): Promise<ExitCode> {\n const [rawTeam, audience, ...extra] = rest;\n const team = rawTeam?.trim().toLowerCase();\n if (!team || !/^[a-z0-9][a-z0-9-]*$/.test(team)) {\n throw usageError(\n rawTeam\n ? `\"${rawTeam}\" is not a team slug.`\n : 'teams audience needs a team.',\n USAGE,\n );\n }\n if (extra.length > 0) {\n throw usageError(`Unexpected argument \"${extra[0]}\".`, USAGE);\n }\n const member =\n typeof args.flags?.member === 'string'\n ? args.flags.member.trim().toLowerCase()\n : undefined;\n const inherit = args.flags?.inherit === true;\n if (inherit && !member) {\n throw usageError('--inherit clears one member’s audience.', USAGE);\n }\n if (inherit && audience) {\n throw usageError(\n 'Name an audience or pass --inherit, not both.',\n 'ekanos teams audience <team> --member <email> --inherit puts them back on the team’s.',\n );\n }\n if (member && !/^[^@\\s]+@[^@\\s]+$/.test(member)) {\n throw usageError(`\"${member}\" is not an email address.`, USAGE);\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n const client = new TeamsClient(env, resolved.session);\n const source = resolved.source;\n const target = { source, team };\n\n if (member) {\n const person = { ...target, email: member };\n const current = await client.call((token) =>\n showMemberAudience(env.host, token, person),\n );\n if (!audience && !inherit) {\n return ctx.succeed(\n { host: env.host, ...current },\n describeMember(ctx, current),\n );\n }\n\n const next = inherit\n ? (\n await client.call((token) =>\n showTeamAudience(env.host, token, target),\n )\n ).audience.id\n : audience!;\n await requireYesIfNarrowing(client, env.host, {\n source,\n from: current.audience,\n to: next,\n who: `${member}`,\n yes: args.yes,\n retry: `ekanos teams audience ${team} ${inherit ? '' : `${quote(audience!)} `}--member ${member}${inherit ? ' --inherit' : ''} --source ${source} --yes`,\n });\n const result = await client.call((token) =>\n setMemberAudience(env.host, token, person, inherit ? null : audience!),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n describeMember(ctx, result, result.before),\n );\n }\n\n const current = await client.call((token) =>\n showTeamAudience(env.host, token, target),\n );\n if (!audience) {\n return ctx.succeed(\n { host: env.host, ...current },\n describeTeam(ctx, current),\n );\n }\n await requireYesIfNarrowing(client, env.host, {\n source,\n from: current.audience,\n to: audience,\n who: `members of ${team} on the team default`,\n yes: args.yes,\n retry: `ekanos teams audience ${team} ${quote(audience)} --source ${source} --yes`,\n });\n const result = await client.call((token) =>\n setTeamAudience(env.host, token, target, audience),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n describeTeam(ctx, result, result.before),\n );\n}\n\n/**\n * Refuses, before any write, a move to an audience that shows less than the\n * one people are on, unless `--yes`. An audience that shows every entitled\n * product can only be left for a narrower one, which is also refused.\n */\nasync function requireYesIfNarrowing(\n client: TeamsClient,\n host: string,\n input: {\n source: string;\n from: AudienceRef;\n to: string;\n who: string;\n yes: boolean;\n retry: string;\n },\n): Promise<void> {\n if (input.yes) return;\n const { audiences } = await client.call((token) =>\n listAudiences(host, token, input.source),\n );\n const from = audiences.find((entry) => entry.id === input.from.id);\n const to = findAudience(audiences, input.to);\n if (!from || !to || to.includesAllEntitled) return;\n\n const kept = new Set(to.products.map((product) => product.slug));\n const lost = from.includesAllEntitled\n ? null\n : from.products.filter((product) => !kept.has(product.slug));\n if (lost !== null && lost.length === 0) return;\n\n throw invalidStateError(\n lost === null\n ? `${to.name} does not show every product the Source has, as ${from.name} does: ${input.who} may stop seeing some in the app.`\n : `${input.who} would stop seeing ${lost.map((product) => product.slug).join(', ')} in the app: ${from.name} shows ${lost.length === 1 ? 'it' : 'them'}, ${to.name} does not.`,\n `Re-run with --yes: ${input.retry}`,\n );\n}\n\nfunction findAudience(\n audiences: Audience[],\n ref: string,\n): Audience | undefined {\n const wanted = ref.trim().toLowerCase();\n return audiences.find(\n (entry) => entry.id === wanted || entry.name.toLowerCase() === wanted,\n );\n}\n\nfunction describeTeam(\n ctx: CliContext,\n result: TeamAudience,\n before?: AudienceRef | null,\n): string {\n return ctx.ui.result({\n title: `${result.team.slug} starts its members on ${result.audience.name}`,\n rows: [\n ['Audience', result.audience.name],\n ...(before !== undefined\n ? ([['Before', before?.name ?? 'none']] as Array<[string, string]>)\n : []),\n ],\n notes: [\n 'A member’s own audience overrides it: \"ekanos teams audience <team> <audience> --member <email>\".',\n '\"ekanos audiences show <audience>\" lists what it shows.',\n ],\n });\n}\n\nfunction describeMember(\n ctx: CliContext,\n result: MemberAudience,\n before?: AudienceRef | null,\n): string {\n return ctx.ui.result({\n title: `${result.member.email} is on ${result.audience.name}`,\n rows: [\n ['Audience', result.audience.name],\n [\n 'From',\n result.isOverride ? 'their own' : `the ${result.team.slug} default`,\n ],\n ...(before !== undefined\n ? ([['Before', before?.name ?? 'none']] as Array<[string, string]>)\n : []),\n ],\n });\n}\n\nfunction quote(name: string): string {\n return /^[A-Za-z0-9._-]+$/.test(name) ? name : `\"${name}\"`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"teams-audience.js","sourceRoot":"","sources":["../../src/commands/teams-audience.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Audience,\n AudienceRef,\n MemberAudience,\n TeamAudience,\n} from '@ekanos/integration-schema';\n\nimport { requireSession, resolveAuthEnvironment } from '../auth/session';\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport {\n listAudiences,\n setMemberAudience,\n setTeamAudience,\n showMemberAudience,\n showTeamAudience,\n} from '../teams-api';\nimport { TeamsClient, type TeamsArgs } from './teams';\n\nconst USAGE =\n 'Run \"ekanos teams audience <team>\" to read a team’s audience (its business type), \"ekanos teams audience <team> <audience> [--yes]\" to set it, or add --member <email> to read one person’s.';\n\n/**\n * `teams audience <team> [<audience>] [--member <email> [--inherit]]` — the\n * team's audience (its business type), which every member is on; their\n * groups narrow it (`teams groups`). Without an audience it reads. Moving\n * people to an audience that shows fewer products hides the difference from\n * them in the app, so that needs `--yes`. `teams scope` is the deprecated\n * form of this.\n *\n * `--member <email>` reads one person's. Setting it (`<audience>` or\n * `--inherit`) is deprecated: a host on plan 258 refuses a per-person\n * audience (`AUDIENCE_SET_ON_TEAM`), and an older host still takes it.\n */\nexport async function runTeamAudience(\n ctx: CliContext,\n args: TeamsArgs,\n rest: readonly string[],\n): Promise<ExitCode> {\n const [rawTeam, audience, ...extra] = rest;\n const team = rawTeam?.trim().toLowerCase();\n if (!team || !/^[a-z0-9][a-z0-9-]*$/.test(team)) {\n throw usageError(\n rawTeam\n ? `\"${rawTeam}\" is not a team slug.`\n : 'teams audience needs a team.',\n USAGE,\n );\n }\n if (extra.length > 0) {\n throw usageError(`Unexpected argument \"${extra[0]}\".`, USAGE);\n }\n const member =\n typeof args.flags?.member === 'string'\n ? args.flags.member.trim().toLowerCase()\n : undefined;\n const inherit = args.flags?.inherit === true;\n if (inherit && !member) {\n throw usageError('--inherit clears one member’s audience.', USAGE);\n }\n if (inherit && audience) {\n throw usageError(\n 'Name an audience or pass --inherit, not both.',\n 'ekanos teams audience <team> --member <email> --inherit puts them back on the team’s.',\n );\n }\n if (member && !/^[^@\\s]+@[^@\\s]+$/.test(member)) {\n throw usageError(`\"${member}\" is not an email address.`, USAGE);\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n const client = new TeamsClient(env, resolved.session);\n const source = resolved.source;\n const target = { source, team };\n\n if (member) {\n const person = { ...target, email: member };\n const current = await client.call((token) =>\n showMemberAudience(env.host, token, person),\n );\n if (!audience && !inherit) {\n return ctx.succeed(\n { host: env.host, ...current },\n describeMember(ctx, current),\n );\n }\n if (inherit && !current.isOverride) {\n return ctx.succeed(\n { host: env.host, ...current, before: current.audience },\n describeMember(ctx, current, current.audience),\n );\n }\n ctx.warn(memberAudienceDeprecationNotice(team));\n\n const next = inherit\n ? (\n await client.call((token) =>\n showTeamAudience(env.host, token, target),\n )\n ).audience.id\n : audience!;\n await requireYesIfNarrowing(client, env.host, {\n source,\n from: current.audience,\n to: next,\n who: `${member}`,\n yes: args.yes,\n retry: `ekanos teams audience ${team} ${inherit ? '' : `${quote(audience!)} `}--member ${member}${inherit ? ' --inherit' : ''} --source ${source} --yes`,\n });\n const result = await client.call((token) =>\n setMemberAudience(env.host, token, person, inherit ? null : audience!),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n describeMember(ctx, result, result.before),\n );\n }\n\n const current = await client.call((token) =>\n showTeamAudience(env.host, token, target),\n );\n if (!audience) {\n return ctx.succeed(\n { host: env.host, ...current },\n describeTeam(ctx, current),\n );\n }\n await requireYesIfNarrowing(client, env.host, {\n source,\n from: current.audience,\n to: audience,\n who: `members of ${team}`,\n yes: args.yes,\n retry: `ekanos teams audience ${team} ${quote(audience)} --source ${source} --yes`,\n });\n const result = await client.call((token) =>\n setTeamAudience(env.host, token, target, audience),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n describeTeam(ctx, result, result.before),\n );\n}\n\n/**\n * Refuses, before any write, a move to an audience that shows less than the\n * one people are on, unless `--yes`. An audience that shows every entitled\n * product can only be left for a narrower one, which is also refused.\n */\nasync function requireYesIfNarrowing(\n client: TeamsClient,\n host: string,\n input: {\n source: string;\n from: AudienceRef;\n to: string;\n who: string;\n yes: boolean;\n retry: string;\n },\n): Promise<void> {\n if (input.yes) return;\n const { audiences } = await client.call((token) =>\n listAudiences(host, token, input.source),\n );\n const from = audiences.find((entry) => entry.id === input.from.id);\n const to = findAudience(audiences, input.to);\n if (!from || !to || to.includesAllEntitled) return;\n\n const kept = new Set(to.products.map((product) => product.slug));\n const lost = from.includesAllEntitled\n ? null\n : from.products.filter((product) => !kept.has(product.slug));\n if (lost !== null && lost.length === 0) return;\n\n throw invalidStateError(\n lost === null\n ? `${to.name} does not show every product the Source has, as ${from.name} does: ${input.who} may stop seeing some in the app.`\n : `${input.who} would stop seeing ${lost.map((product) => product.slug).join(', ')} in the app: ${from.name} shows ${lost.length === 1 ? 'it' : 'them'}, ${to.name} does not.`,\n `Re-run with --yes: ${input.retry}`,\n );\n}\n\nfunction findAudience(\n audiences: Audience[],\n ref: string,\n): Audience | undefined {\n const wanted = ref.trim().toLowerCase();\n return audiences.find(\n (entry) => entry.id === wanted || entry.name.toLowerCase() === wanted,\n );\n}\n\nfunction describeTeam(\n ctx: CliContext,\n result: TeamAudience,\n before?: AudienceRef | null,\n): string {\n return ctx.ui.result({\n title: `${result.team.slug} is on ${result.audience.name}`,\n rows: [\n ['Audience', result.audience.name],\n ...(before !== undefined\n ? ([['Before', before?.name ?? 'none']] as Array<[string, string]>)\n : []),\n ],\n notes: [\n `Every member is on it; their groups narrow it: \"ekanos teams groups list ${result.team.slug}\".`,\n '\"ekanos audiences show <audience>\" lists what it shows.',\n ],\n });\n}\n\nfunction describeMember(\n ctx: CliContext,\n result: MemberAudience,\n before?: AudienceRef | null,\n): string {\n return ctx.ui.result({\n title: `${result.member.email} is on ${result.audience.name}`,\n rows: [\n ['Audience', result.audience.name],\n [\n 'From',\n result.isOverride ? 'their own' : `the ${result.team.slug} audience`,\n ],\n ...(before !== undefined\n ? ([['Before', before?.name ?? 'none']] as Array<[string, string]>)\n : []),\n ],\n });\n}\n\n/**\n * The one line a per-person audience write prints (to stderr, so JSON on\n * stdout is unchanged) before it is sent.\n */\nexport function memberAudienceDeprecationNotice(team: string): string {\n return `Deprecated: a person’s access is set by the team’s audience and their groups. Hosts on the audiences model refuse this (AUDIENCE_SET_ON_TEAM); set the team’s with \"ekanos teams audience ${team} <audience>\", or add them to a group with \"ekanos teams groups members add ${team} <group> <email>\".`;\n}\n\nfunction quote(name: string): string {\n return /^[A-Za-z0-9._-]+$/.test(name) ? name : `\"${name}\"`;\n}\n"]}
|
|
@@ -377,10 +377,16 @@ export async function confirmChange(ctx, args, confirm) {
|
|
|
377
377
|
function groupRow(group) {
|
|
378
378
|
var _a;
|
|
379
379
|
return [
|
|
380
|
-
group.
|
|
380
|
+
group.kind === 'predefined'
|
|
381
|
+
? `${group.name} (predefined)`
|
|
382
|
+
: group.kind === 'everyone'
|
|
383
|
+
? `${group.name} (everyone in no other group)`
|
|
384
|
+
: group.name,
|
|
381
385
|
[
|
|
382
386
|
(_a = group.description) !== null && _a !== void 0 ? _a : 'no description',
|
|
383
|
-
|
|
387
|
+
group.kind === 'everyone'
|
|
388
|
+
? 'members: everyone on the team in no other group'
|
|
389
|
+
: `members: ${group.members.length === 0 ? 'none' : group.members.map((member) => { var _a; return (_a = member.email) !== null && _a !== void 0 ? _a : member.userId; }).join(', ')}`,
|
|
384
390
|
`products: ${group.products.length === 0 ? 'none (no narrowing)' : group.products.map((product) => product.slug).join(', ')}`,
|
|
385
391
|
],
|
|
386
392
|
];
|